blob: 363ff2e8b7ec2dcf65c4292e500121412c0f4d2e [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 Cercueil1be57832014-03-11 16:27:16 +010022#include <dirent.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010023#include <errno.h>
Lars-Peter Clausenea5ea6f2016-04-21 18:23:38 +020024#include <limits.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>
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +020030#include <sys/eventfd.h>
Paul Cercueil92f46df2014-04-28 13:17:53 +020031#include <sys/ioctl.h>
32#include <sys/mman.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010033#include <sys/types.h>
34#include <sys/stat.h>
35#include <unistd.h>
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +020036#include <string.h>
Lars-Peter Clausen00f80092014-07-01 17:52:05 +020037#include <sys/utsname.h>
Lars-Peter Clausenb22da002016-04-21 14:58:53 +020038#include <time.h>
Romain Roffécead1da2015-06-30 13:35:51 +020039#include <unistd.h>
Romain Roffé6ce74a22015-06-30 11:45:11 +020040#include <fcntl.h>
Paul Cercueile6be0702016-11-18 10:57:23 +010041#ifdef WITH_LOCAL_CONFIG
42#include <ini.h>
43#endif
Paul Cercueil0b2ce712014-02-17 15:04:18 +010044
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020045#define DEFAULT_TIMEOUT_MS 1000
46
Paul Cercueil92f46df2014-04-28 13:17:53 +020047#define NB_BLOCKS 4
48
49#define BLOCK_ALLOC_IOCTL _IOWR('i', 0xa0, struct block_alloc_req)
50#define BLOCK_FREE_IOCTL _IO('i', 0xa1)
51#define BLOCK_QUERY_IOCTL _IOWR('i', 0xa2, struct block)
52#define BLOCK_ENQUEUE_IOCTL _IOWR('i', 0xa3, struct block)
53#define BLOCK_DEQUEUE_IOCTL _IOWR('i', 0xa4, struct block)
54
Paul Cercueil71694c72014-05-22 14:02:13 +020055#define BLOCK_FLAG_CYCLIC BIT(1)
56
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020057/* Forward declarations */
58static ssize_t local_read_dev_attr(const struct iio_device *dev,
59 const char *attr, char *dst, size_t len, bool is_debug);
60static ssize_t local_read_chn_attr(const struct iio_channel *chn,
61 const char *attr, char *dst, size_t len);
Paul Cercueil1da28122014-05-22 10:59:49 +020062static ssize_t local_write_dev_attr(const struct iio_device *dev,
63 const char *attr, const char *src, size_t len, bool is_debug);
64static ssize_t local_write_chn_attr(const struct iio_channel *chn,
65 const char *attr, const char *src, size_t len);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020066
Paul Cercueil92f46df2014-04-28 13:17:53 +020067struct block_alloc_req {
68 uint32_t type,
69 size,
70 count,
71 id;
72};
73
74struct block {
75 uint32_t id,
76 size,
77 bytes_used,
78 type,
79 flags,
80 offset;
81 uint64_t timestamp;
82};
83
Paul Cercueil00558f12016-04-12 14:40:40 +020084struct iio_context_pdata {
Lars-Peter Clausen8068be32016-04-22 10:36:34 +020085 unsigned int rw_timeout_ms;
Paul Cercueil00558f12016-04-12 14:40:40 +020086};
87
Paul Cercueileaab6582014-02-21 09:35:59 +010088struct iio_device_pdata {
Romain Roffé6ce74a22015-06-30 11:45:11 +020089 int fd;
Romain Roffécead1da2015-06-30 13:35:51 +020090 bool blocking;
Paul Cercueil71694c72014-05-22 14:02:13 +020091 unsigned int samples_count, nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +020092
Romain Roffé0f737472015-06-30 16:45:54 +020093 struct block *blocks;
94 void **addrs;
Paul Cercueil92f46df2014-04-28 13:17:53 +020095 int last_dequeued;
Paul Cercueil6ea8a752014-06-03 11:35:35 +020096 bool is_high_speed, cyclic, cyclic_buffer_enqueued, buffer_enabled;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +020097
98 int cancel_fd;
Paul Cercueileaab6582014-02-21 09:35:59 +010099};
100
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200101struct iio_channel_pdata {
Paul Cercueila1a34c62016-08-09 12:53:39 +0200102 char *enable_fn;
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200103};
104
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100105static const char * const device_attrs_blacklist[] = {
106 "dev",
107 "uevent",
108};
109
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200110static int ioctl_nointr(int fd, unsigned long request, void *data)
111{
112 int ret;
113
114 do {
115 ret = ioctl(fd, request, data);
116 } while (ret == -1 && errno == EINTR);
117
118 return ret;
119}
120
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200121static void local_free_channel_pdata(struct iio_channel *chn)
122{
Paul Cercueila1a34c62016-08-09 12:53:39 +0200123 if (chn->pdata) {
124 free(chn->pdata->enable_fn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200125 free(chn->pdata);
Paul Cercueila1a34c62016-08-09 12:53:39 +0200126 }
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200127}
128
Romain Roffé0f737472015-06-30 16:45:54 +0200129static void local_free_pdata(struct iio_device *device)
130{
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200131 unsigned int i;
132
133 for (i = 0; i < device->nb_channels; i++)
134 local_free_channel_pdata(device->channels[i]);
135
136 if (device->pdata) {
Romain Roffé0f737472015-06-30 16:45:54 +0200137 free(device->pdata->blocks);
138 free(device->pdata->addrs);
139 free(device->pdata);
140 }
141}
142
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100143static void local_shutdown(struct iio_context *ctx)
144{
Paul Cercueil42d12352014-05-05 16:11:58 +0200145 /* Free the backend data stored in every device structure */
Paul Cercueil167d3112014-02-18 12:23:53 +0100146 unsigned int i;
Paul Cercueil00558f12016-04-12 14:40:40 +0200147
Paul Cercueilb04d4d12016-08-01 15:46:06 +0200148 for (i = 0; i < ctx->nb_devices; i++) {
149 struct iio_device *dev = ctx->devices[i];
150
151 iio_device_close(dev);
152 local_free_pdata(dev);
153 }
Paul Cercueil00558f12016-04-12 14:40:40 +0200154
155 free(ctx->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100156}
157
Michael Hennerich1c8aa572014-11-06 17:42:30 +0100158/** Shrinks the first nb characters of a string
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100159 * e.g. strcut("foobar", 4) replaces the content with "ar". */
160static void strcut(char *str, int nb)
161{
162 char *ptr = str + nb;
163 while (*ptr)
164 *str++ = *ptr++;
165 *str = 0;
166}
167
168static int set_channel_name(struct iio_channel *chn)
169{
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100170 size_t prefix_len = 0;
171 const char *attr0;
172 const char *ptr;
173 unsigned int i;
174
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100175 if (chn->nb_attrs < 2)
176 return 0;
177
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100178 attr0 = ptr = chn->attrs[0].name;
179
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100180 while (true) {
181 bool can_fix = true;
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100182 size_t len;
183
184 ptr = strchr(ptr, '_');
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100185 if (!ptr)
186 break;
187
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100188 len = ptr - attr0 + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100189 for (i = 1; can_fix && i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200190 can_fix = !strncmp(attr0, chn->attrs[i].name, len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100191
192 if (!can_fix)
193 break;
194
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100195 prefix_len = len;
196 ptr = ptr + 1;
197 }
198
199 if (prefix_len) {
200 char *name;
201
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100202 name = malloc(prefix_len);
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100203 if (!name)
204 return -ENOMEM;
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100205 strncpy(name, attr0, prefix_len - 1);
206 name[prefix_len - 1] = '\0';
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100207 DEBUG("Setting name of channel %s to %s\n", chn->id, name);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100208 chn->name = name;
209
210 /* Shrink the attribute name */
211 for (i = 0; i < chn->nb_attrs; i++)
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100212 strcut(chn->attrs[i].name, prefix_len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100213 }
214
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100215 return 0;
216}
217
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200218/*
219 * Used to generate the timeout parameter for operations like poll. Returns the
220 * number of ms until it is timeout_rel ms after the time specified in start. If
221 * timeout_rel is 0 returns -1 to indicate no timeout.
222 *
223 * The timeout that is specified for IIO operations is the maximum time a buffer
224 * push() or refill() operation should take before returning. poll() is used to
225 * wait for either data activity or for the timeout to elapse. poll() might get
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200226 * interrupted in which case it is called again or the read()/write() operation
227 * might not complete the full buffer size in one call in which case we go back
228 * to poll() again as well. Passing the same timeout as before would increase
229 * the total timeout and if repeated interruptions occur (e.g. by a timer
230 * signal) the operation might never time out or with significant delay. Hence
231 * before each poll() invocation the timeout is recalculated relative to the
232 * start of refill() or push() operation.
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200233 */
234static int get_rel_timeout_ms(struct timespec *start, unsigned int timeout_rel)
235{
236 struct timespec now;
237 int diff_ms;
238
239 if (timeout_rel == 0) /* No timeout */
240 return -1;
241
242 clock_gettime(CLOCK_MONOTONIC, &now);
243
244 diff_ms = (now.tv_sec - start->tv_sec) * 1000;
245 diff_ms += (now.tv_nsec - start->tv_nsec) / 1000000;
246
247 if (diff_ms >= timeout_rel) /* Expired */
248 return 0;
249 if (diff_ms > 0) /* Should never be false, but lets be safe */
250 timeout_rel -= diff_ms;
251 if (timeout_rel > INT_MAX)
252 return INT_MAX;
253
254 return (int) timeout_rel;
255}
256
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200257static int device_check_ready(const struct iio_device *dev, short events,
258 struct timespec *start)
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200259{
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200260 struct pollfd pollfd[2] = {
261 {
262 .fd = dev->pdata->fd,
263 .events = events,
264 }, {
265 .fd = dev->pdata->cancel_fd,
266 .events = POLLIN,
267 }
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200268 };
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200269 unsigned int rw_timeout_ms = dev->ctx->pdata->rw_timeout_ms;
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200270 int timeout_rel;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200271 int ret;
272
Romain Roffécead1da2015-06-30 13:35:51 +0200273 if (!dev->pdata->blocking)
274 return 0;
275
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200276 do {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200277 timeout_rel = get_rel_timeout_ms(start, rw_timeout_ms);
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200278 ret = poll(pollfd, 2, timeout_rel);
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200279 } while (ret == -1 && errno == EINTR);
280
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200281 if ((pollfd[1].revents & POLLIN))
282 return -EBADF;
283
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200284 if (ret < 0)
285 return -errno;
286 if (!ret)
287 return -ETIMEDOUT;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200288 if (pollfd[0].revents & POLLNVAL)
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200289 return -EBADF;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200290 if (!(pollfd[0].revents & events))
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200291 return -EIO;
292 return 0;
293}
294
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200295static ssize_t local_read(const struct iio_device *dev,
296 void *dst, size_t len, uint32_t *mask, size_t words)
Romain Roffé6ce74a22015-06-30 11:45:11 +0200297{
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200298 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200299 uintptr_t ptr = (uintptr_t) dst;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200300 struct timespec start;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200301 ssize_t readsize;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200302 ssize_t ret;
303
304 if (pdata->fd == -1)
305 return -EBADF;
306 if (words != dev->words)
307 return -EINVAL;
308
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200309 memcpy(mask, dev->mask, words);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200310
Lars-Peter Clausen8ba0d5b2016-02-17 11:30:23 +0100311 if (len == 0)
312 return 0;
313
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200314 clock_gettime(CLOCK_MONOTONIC, &start);
Lars-Peter Clausen525c93e2016-04-21 14:05:27 +0200315
Romain Roffé6ce74a22015-06-30 11:45:11 +0200316 while (len > 0) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200317 ret = device_check_ready(dev, POLLIN, &start);
318 if (ret < 0)
319 break;
320
Romain Roffé6ce74a22015-06-30 11:45:11 +0200321 do {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200322 ret = read(pdata->fd, (void *) ptr, len);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200323 } while (ret == -1 && errno == EINTR);
324
325 if (ret == -1) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200326 if (pdata->blocking && errno == EAGAIN)
327 continue;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200328 ret = -EIO;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200329 break;
330 } else if (ret == 0) {
331 ret = -EIO;
332 break;
333 }
334
335 ptr += ret;
336 len -= ret;
337 }
338
339 readsize = (ssize_t)(ptr - (uintptr_t) dst);
Romain Roffécead1da2015-06-30 13:35:51 +0200340 if ((ret > 0 || ret == -EAGAIN) && (readsize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200341 return readsize;
342 else
343 return ret;
344}
345
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200346static ssize_t local_write(const struct iio_device *dev,
347 const void *src, size_t len)
Romain Roffé6ce74a22015-06-30 11:45:11 +0200348{
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200349 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200350 uintptr_t ptr = (uintptr_t) src;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200351 struct timespec start;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200352 ssize_t writtensize;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200353 ssize_t ret;
354
355 if (pdata->fd == -1)
356 return -EBADF;
357
Lars-Peter Clausen525c93e2016-04-21 14:05:27 +0200358 if (len == 0)
359 return 0;
360
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200361 clock_gettime(CLOCK_MONOTONIC, &start);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200362
363 while (len > 0) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200364 ret = device_check_ready(dev, POLLOUT, &start);
365 if (ret < 0)
366 break;
367
Romain Roffé6ce74a22015-06-30 11:45:11 +0200368 do {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200369 ret = write(pdata->fd, (void *) ptr, len);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200370 } while (ret == -1 && errno == EINTR);
371
372 if (ret == -1) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200373 if (pdata->blocking && errno == EAGAIN)
374 continue;
375
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200376 ret = -EIO;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200377 break;
378 } else if (ret == 0) {
379 ret = -EIO;
380 break;
381 }
382
383 ptr += ret;
384 len -= ret;
385 }
386
387 writtensize = (ssize_t)(ptr - (uintptr_t) src);
Romain Roffécead1da2015-06-30 13:35:51 +0200388 if ((ret > 0 || ret == -EAGAIN) && (writtensize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200389 return writtensize;
390 else
391 return ret;
392}
393
Romain Roffécead1da2015-06-30 13:35:51 +0200394static ssize_t local_enable_buffer(const struct iio_device *dev)
395{
396 struct iio_device_pdata *pdata = dev->pdata;
397 ssize_t ret = 0;
398
399 if (!pdata->buffer_enabled) {
400 ret = local_write_dev_attr(dev,
401 "buffer/enable", "1", 2, false);
402 if (ret >= 0)
403 pdata->buffer_enabled = true;
404 }
405
406 return 0;
407}
Romain Roffé6ce74a22015-06-30 11:45:11 +0200408
Romain Roffé0f737472015-06-30 16:45:54 +0200409static int local_set_kernel_buffers_count(const struct iio_device *dev,
410 unsigned int nb_blocks)
411{
412 struct iio_device_pdata *pdata = dev->pdata;
413
414 if (pdata->fd != -1)
415 return -EBUSY;
416
417 pdata->nb_blocks = nb_blocks;
418
419 return 0;
420}
421
Paul Cercueil92f46df2014-04-28 13:17:53 +0200422static ssize_t local_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100423 void **addr_ptr, size_t bytes_used,
424 uint32_t *mask, size_t words)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200425{
426 struct block block;
427 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200428 struct timespec start;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200429 char err_str[1024];
Romain Roffé6ce74a22015-06-30 11:45:11 +0200430 int f = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200431 ssize_t ret;
432
433 if (!pdata->is_high_speed)
434 return -ENOSYS;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200435 if (f == -1)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200436 return -EBADF;
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200437 if (!addr_ptr)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200438 return -EINVAL;
439
Paul Cercueil92f46df2014-04-28 13:17:53 +0200440 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200441 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200442
443 if (pdata->cyclic) {
444 if (pdata->cyclic_buffer_enqueued)
445 return -EBUSY;
446 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
447 pdata->cyclic_buffer_enqueued = true;
448 }
449
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200450 last_block->bytes_used = bytes_used;
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200451 ret = (ssize_t) ioctl_nointr(f,
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200452 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200453 if (ret) {
454 ret = (ssize_t) -errno;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200455 iio_strerror(errno, err_str, sizeof(err_str));
456 ERROR("Unable to enqueue block: %s\n", err_str);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200457 return ret;
458 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200459
460 if (pdata->cyclic) {
461 *addr_ptr = pdata->addrs[pdata->last_dequeued];
462 return (ssize_t) last_block->bytes_used;
463 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200464 }
465
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200466 clock_gettime(CLOCK_MONOTONIC, &start);
Lars-Peter Clausene63811e2016-04-21 11:22:33 +0200467
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200468 do {
469 ret = (ssize_t) device_check_ready(dev, POLLIN | POLLOUT, &start);
470 if (ret < 0)
471 return ret;
472
473 memset(&block, 0, sizeof(block));
474 ret = (ssize_t) ioctl_nointr(f, BLOCK_DEQUEUE_IOCTL, &block);
475 } while (pdata->blocking && ret == -1 && errno == EAGAIN);
476
Paul Cercueil92f46df2014-04-28 13:17:53 +0200477 if (ret) {
478 ret = (ssize_t) -errno;
Paul Cercueilea51a3f2016-05-25 17:22:03 +0200479 if ((!pdata->blocking && ret != -EAGAIN) ||
480 (pdata->blocking && ret != -ETIMEDOUT)) {
Lars-Peter Clausenf8408352016-04-25 10:43:11 +0200481 iio_strerror(errno, err_str, sizeof(err_str));
482 ERROR("Unable to dequeue block: %s\n", err_str);
483 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200484 return ret;
485 }
486
Paul Cercueil558ade42014-11-27 10:59:48 +0100487 /* Requested buffer size is too big! */
488 if (pdata->last_dequeued < 0 && bytes_used != block.size)
489 return -EFBIG;
490
Paul Cercueil92f46df2014-04-28 13:17:53 +0200491 pdata->last_dequeued = block.id;
492 *addr_ptr = pdata->addrs[block.id];
493 return (ssize_t) block.bytes_used;
494}
495
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200496static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
497 char *dst, size_t len, bool is_debug)
498{
499 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
500 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
501 char *ptr = dst;
502
503 for (i = 0; len >= 4 && i < nb; i++) {
504 /* Recursive! */
505 ssize_t ret = local_read_dev_attr(dev, attrs[i],
506 ptr + 4, len - 4, is_debug);
Paul Cercueil2042c902016-04-25 18:43:45 +0200507 *(uint32_t *) ptr = iio_htobe32(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200508
509 /* Align the length to 4 bytes */
510 if (ret > 0 && ret & 3)
511 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200512 ptr += 4 + (ret < 0 ? 0 : ret);
513 len -= 4 + (ret < 0 ? 0 : ret);
514 }
515
516 return ptr - dst;
517}
518
519static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
520 char *dst, size_t len)
521{
522 unsigned int i;
523 char *ptr = dst;
524
525 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
526 /* Recursive! */
527 ssize_t ret = local_read_chn_attr(chn,
528 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil2042c902016-04-25 18:43:45 +0200529 *(uint32_t *) ptr = iio_htobe32(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200530
531 /* Align the length to 4 bytes */
532 if (ret > 0 && ret & 3)
533 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200534 ptr += 4 + (ret < 0 ? 0 : ret);
535 len -= 4 + (ret < 0 ? 0 : ret);
536 }
537
538 return ptr - dst;
539}
540
Paul Cercueil1da28122014-05-22 10:59:49 +0200541static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
542{
543 while (nb--) {
544 int32_t val;
545
546 if (len < 4)
547 return -EINVAL;
548
Paul Cercueil2042c902016-04-25 18:43:45 +0200549 val = (int32_t) iio_be32toh(*(uint32_t *) src);
Paul Cercueil1da28122014-05-22 10:59:49 +0200550 src += 4;
551 len -= 4;
552
553 if (val > 0) {
554 if ((uint32_t) val > len)
555 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200556
557 /* Align the length to 4 bytes */
558 if (val & 3)
559 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200560 len -= val;
561 src += val;
562 }
563 }
564
565 /* We should have analyzed the whole buffer by now */
566 return !len ? 0 : -EINVAL;
567}
568
569static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
570 const char *src, size_t len, bool is_debug)
571{
572 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
573 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
574 const char *ptr = src;
575
576 /* First step: Verify that the buffer is in the correct format */
577 if (local_buffer_analyze(nb, src, len))
578 return -EINVAL;
579
580 /* Second step: write the attributes */
581 for (i = 0; i < nb; i++) {
Paul Cercueil2042c902016-04-25 18:43:45 +0200582 int32_t val = (int32_t) iio_be32toh(*(uint32_t *) ptr);
Paul Cercueil1da28122014-05-22 10:59:49 +0200583 ptr += 4;
584
585 if (val > 0) {
586 local_write_dev_attr(dev, attrs[i], ptr, val, is_debug);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200587
588 /* Align the length to 4 bytes */
589 if (val & 3)
590 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200591 ptr += val;
592 }
593 }
594
595 return ptr - src;
596}
597
598static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
599 const char *src, size_t len)
600{
601 unsigned int i, nb = chn->nb_attrs;
602 const char *ptr = src;
603
604 /* First step: Verify that the buffer is in the correct format */
605 if (local_buffer_analyze(nb, src, len))
606 return -EINVAL;
607
608 /* Second step: write the attributes */
609 for (i = 0; i < nb; i++) {
Paul Cercueil2042c902016-04-25 18:43:45 +0200610 int32_t val = (int32_t) iio_be32toh(*(uint32_t *) ptr);
Paul Cercueil1da28122014-05-22 10:59:49 +0200611 ptr += 4;
612
613 if (val > 0) {
614 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200615
616 /* Align the length to 4 bytes */
617 if (val & 3)
618 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200619 ptr += val;
620 }
621 }
622
623 return ptr - src;
624}
625
Paul Cercueil167d3112014-02-18 12:23:53 +0100626static ssize_t local_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200627 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100628{
Paul Cercueil3e898302014-02-17 16:17:11 +0100629 FILE *f;
630 char buf[1024];
631 ssize_t ret;
632
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200633 if (!attr)
634 return local_read_all_dev_attrs(dev, dst, len, is_debug);
635
Paul Cercueil50c762a2014-04-14 15:55:43 +0200636 if (is_debug)
637 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
638 dev->id, attr);
639 else
640 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
641 dev->id, attr);
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100642 f = fopen(buf, "re");
Paul Cercueil3e898302014-02-17 16:17:11 +0100643 if (!f)
644 return -errno;
645
646 ret = fread(dst, 1, len, f);
647 if (ret > 0)
648 dst[ret - 1] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100649 fflush(f);
650 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200651 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100652 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200653 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100654}
655
Paul Cercueil167d3112014-02-18 12:23:53 +0100656static ssize_t local_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200657 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100658{
Paul Cercueil3e898302014-02-17 16:17:11 +0100659 FILE *f;
660 char buf[1024];
661 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100662
Paul Cercueil1da28122014-05-22 10:59:49 +0200663 if (!attr)
664 return local_write_all_dev_attrs(dev, src, len, is_debug);
665
Paul Cercueil50c762a2014-04-14 15:55:43 +0200666 if (is_debug)
667 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
668 dev->id, attr);
669 else
670 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
671 dev->id, attr);
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100672 f = fopen(buf, "we");
Paul Cercueil3e898302014-02-17 16:17:11 +0100673 if (!f)
674 return -errno;
675
676 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100677 fflush(f);
678 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200679 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100680 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200681 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100682}
683
Paul Cercueil167d3112014-02-18 12:23:53 +0100684static const char * get_filename(const struct iio_channel *chn,
685 const char *attr)
686{
Paul Cercueil167d3112014-02-18 12:23:53 +0100687 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200688 for (i = 0; i < chn->nb_attrs; i++)
689 if (!strcmp(attr, chn->attrs[i].name))
690 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100691 return attr;
692}
693
694static ssize_t local_read_chn_attr(const struct iio_channel *chn,
695 const char *attr, char *dst, size_t len)
696{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200697 if (!attr)
698 return local_read_all_chn_attrs(chn, dst, len);
699
Paul Cercueil167d3112014-02-18 12:23:53 +0100700 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200701 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100702}
703
704static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200705 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100706{
Paul Cercueil1da28122014-05-22 10:59:49 +0200707 if (!attr)
708 return local_write_all_chn_attrs(chn, src, len);
709
Paul Cercueil167d3112014-02-18 12:23:53 +0100710 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200711 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100712}
713
Paul Cercueilff778232014-03-24 14:23:08 +0100714static int channel_write_state(const struct iio_channel *chn)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100715{
Paul Cercueilff778232014-03-24 14:23:08 +0100716 char *en = iio_channel_is_enabled(chn) ? "1" : "0";
Paul Cercueila1a34c62016-08-09 12:53:39 +0200717 ssize_t ret;
718
719 if (!chn->pdata || !chn->pdata->enable_fn) {
720 ERROR("Libiio bug: No \"en\" attribute parsed\n");
721 return -EINVAL;
722 }
723
724 ret = local_write_chn_attr(chn, chn->pdata->enable_fn, en, 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100725 if (ret < 0)
726 return (int) ret;
727 else
728 return 0;
729}
730
Paul Cercueil92f46df2014-04-28 13:17:53 +0200731static int enable_high_speed(const struct iio_device *dev)
732{
733 struct block_alloc_req req;
734 struct iio_device_pdata *pdata = dev->pdata;
735 unsigned int i;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200736 int ret, fd = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200737
Paul Cercueil71694c72014-05-22 14:02:13 +0200738 if (pdata->cyclic) {
739 pdata->nb_blocks = 1;
740 DEBUG("Enabling cyclic mode\n");
741 } else {
Paul Cercueil71694c72014-05-22 14:02:13 +0200742 DEBUG("Cyclic mode not enabled\n");
743 }
744
Romain Roffé0f737472015-06-30 16:45:54 +0200745 pdata->blocks = calloc(pdata->nb_blocks, sizeof(*pdata->blocks));
746 if (!pdata->blocks) {
747 pdata->nb_blocks = 0;
748 return -ENOMEM;
749 }
750
751 pdata->addrs = calloc(pdata->nb_blocks, sizeof(*pdata->addrs));
752 if (!pdata->addrs) {
753 free(pdata->blocks);
754 pdata->blocks = NULL;
755 return -ENOMEM;
756 }
757
Paul Cercueil1fa913d2015-04-28 16:30:53 +0200758 req.id = 0;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200759 req.type = 0;
760 req.size = pdata->samples_count *
761 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Paul Cercueil71694c72014-05-22 14:02:13 +0200762 req.count = pdata->nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200763
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200764 ret = ioctl_nointr(fd, BLOCK_ALLOC_IOCTL, &req);
Romain Roffé0f737472015-06-30 16:45:54 +0200765 if (ret < 0) {
766 ret = -errno;
767 goto err_freemem;
768 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200769
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200770 /* We might get less blocks than what we asked for */
771 pdata->nb_blocks = req.count;
772
Paul Cercueil92f46df2014-04-28 13:17:53 +0200773 /* mmap all the blocks */
Paul Cercueil71694c72014-05-22 14:02:13 +0200774 for (i = 0; i < pdata->nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200775 pdata->blocks[i].id = i;
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200776 ret = ioctl_nointr(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200777 if (ret) {
778 ret = -errno;
779 goto err_munmap;
780 }
781
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200782 ret = ioctl_nointr(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200783 if (ret) {
784 ret = -errno;
785 goto err_munmap;
786 }
787
Paul Cercueil032a5652014-05-12 17:11:19 +0200788 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
789 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200790 MAP_SHARED, fd, pdata->blocks[i].offset);
791 if (pdata->addrs[i] == MAP_FAILED) {
792 ret = -errno;
793 goto err_munmap;
794 }
795 }
796
Paul Cercueil4a702d32014-05-12 17:02:37 +0200797 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200798 return 0;
799
800err_munmap:
801 for (; i > 0; i--)
802 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200803 ioctl_nointr(fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200804err_freemem:
805 free(pdata->addrs);
806 pdata->addrs = NULL;
807 free(pdata->blocks);
808 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200809 return ret;
810}
811
Paul Cercueil92f15c22015-04-20 11:36:51 +0200812static int local_open(const struct iio_device *dev,
813 size_t samples_count, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100814{
815 unsigned int i;
816 int ret;
817 char buf[1024];
818 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200819
Romain Roffé6ce74a22015-06-30 11:45:11 +0200820 if (pdata->fd != -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100821 return -EBUSY;
822
Paul Cercueilcecda352014-05-06 18:14:29 +0200823 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200824 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100825 return ret;
826
Paul Cercueil11334342015-06-23 16:55:35 +0200827 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200828 ret = local_write_dev_attr(dev, "buffer/length",
829 buf, strlen(buf) + 1, false);
830 if (ret < 0)
831 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200832
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200833 pdata->cancel_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
834 if (pdata->cancel_fd == -1)
835 return -errno;
836
Paul Cercueil8c29e412014-04-07 09:46:45 +0200837 snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200838 pdata->fd = open(buf, O_RDWR | O_CLOEXEC | O_NONBLOCK);
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200839 if (pdata->fd == -1) {
840 ret = -errno;
841 goto err_close_cancel_fd;
842 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100843
Paul Cercueil11334342015-06-23 16:55:35 +0200844 /* Disable channels */
845 for (i = 0; i < dev->nb_channels; i++) {
846 struct iio_channel *chn = dev->channels[i];
847 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
848 ret = channel_write_state(chn);
849 if (ret < 0)
850 goto err_close;
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100851 }
Paul Cercueil11334342015-06-23 16:55:35 +0200852 }
853 /* Enable channels */
854 for (i = 0; i < dev->nb_channels; i++) {
855 struct iio_channel *chn = dev->channels[i];
856 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
857 ret = channel_write_state(chn);
858 if (ret < 0)
859 goto err_close;
Paul Cercueile1311222014-03-12 15:46:16 +0100860 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100861 }
862
Paul Cercueil71694c72014-05-22 14:02:13 +0200863 pdata->cyclic = cyclic;
864 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200865 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200866 pdata->samples_count = samples_count;
Paul Cercueil71694c72014-05-22 14:02:13 +0200867 pdata->is_high_speed = !enable_high_speed(dev);
Paul Cercueilb762fc62014-05-12 16:56:09 +0200868
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200869 if (!pdata->is_high_speed) {
Romain Roffé0f737472015-06-30 16:45:54 +0200870 unsigned long size = samples_count * pdata->nb_blocks;
Paul Cercueil032a5652014-05-12 17:11:19 +0200871 WARNING("High-speed mode not enabled\n");
Paul Cercueiled621ee2015-06-24 10:50:21 +0200872
Lars-Peter Clausen23804792016-04-20 18:17:56 +0200873 /* Cyclic mode is only supported in high-speed mode */
Lars-Peter Clausen3e8774c2016-09-21 16:49:32 +0200874 if (cyclic) {
875 ret = -EPERM;
876 goto err_close;
877 }
Lars-Peter Clausen23804792016-04-20 18:17:56 +0200878
Paul Cercueiled621ee2015-06-24 10:50:21 +0200879 /* Increase the size of the kernel buffer, when using the
880 * low-speed interface. This avoids losing samples when
881 * refilling the iio_buffer. */
Romain Roffé0f737472015-06-30 16:45:54 +0200882 snprintf(buf, sizeof(buf), "%lu", size);
Paul Cercueiled621ee2015-06-24 10:50:21 +0200883 ret = local_write_dev_attr(dev, "buffer/length",
884 buf, strlen(buf) + 1, false);
885 if (ret < 0)
886 goto err_close;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200887 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100888
Lars-Peter Clausen53d6d452016-04-20 17:46:11 +0200889 ret = local_enable_buffer(dev);
890 if (ret < 0)
891 goto err_close;
892
Paul Cercueil45c575d2014-03-20 15:14:01 +0100893 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +0100894err_close:
Romain Roffé6ce74a22015-06-30 11:45:11 +0200895 close(pdata->fd);
896 pdata->fd = -1;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200897err_close_cancel_fd:
898 close(pdata->cancel_fd);
899 pdata->cancel_fd = -1;
Paul Cercueile1311222014-03-12 15:46:16 +0100900 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100901}
902
903static int local_close(const struct iio_device *dev)
904{
905 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100906 int ret;
907
Paul Cercueilb6a40c22015-07-02 11:12:16 +0200908 if (pdata->fd == -1)
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100909 return -EBADF;
910
Paul Cercueil92f46df2014-04-28 13:17:53 +0200911 if (pdata->is_high_speed) {
912 unsigned int i;
Paul Cercueil71694c72014-05-22 14:02:13 +0200913 for (i = 0; i < pdata->nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200914 munmap(pdata->addrs[i], pdata->blocks[i].size);
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200915 ioctl_nointr(pdata->fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200916 free(pdata->addrs);
917 pdata->addrs = NULL;
918 free(pdata->blocks);
919 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200920 }
921
Romain Roffé6ce74a22015-06-30 11:45:11 +0200922 ret = close(pdata->fd);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100923 if (ret)
924 return ret;
925
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200926 close(pdata->cancel_fd);
927
Romain Roffé6ce74a22015-06-30 11:45:11 +0200928 pdata->fd = -1;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200929 pdata->cancel_fd = -1;
930
Paul Cercueil71694c72014-05-22 14:02:13 +0200931 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
932 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100933}
934
Romain Roffé87897862015-06-30 13:34:08 +0200935static int local_get_fd(const struct iio_device *dev)
936{
Paul Cercueil2cdc81b2015-07-02 11:13:23 +0200937 if (dev->pdata->fd == -1)
938 return -EBADF;
939 else
940 return dev->pdata->fd;
Romain Roffé87897862015-06-30 13:34:08 +0200941}
942
Romain Roffécead1da2015-06-30 13:35:51 +0200943static int local_set_blocking_mode(const struct iio_device *dev, bool blocking)
944{
Romain Roffécead1da2015-06-30 13:35:51 +0200945 if (dev->pdata->fd == -1)
946 return -EBADF;
947
948 if (dev->pdata->cyclic)
949 return -EPERM;
950
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200951 dev->pdata->blocking = blocking;
Romain Roffécead1da2015-06-30 13:35:51 +0200952
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200953 return 0;
Romain Roffécead1da2015-06-30 13:35:51 +0200954}
955
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100956static int local_get_trigger(const struct iio_device *dev,
957 const struct iio_device **trigger)
958{
959 char buf[1024];
960 unsigned int i;
961 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +0200962 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +0200963 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100964 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100965 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +0200966 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100967
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200968 if (buf[0] == '\0') {
969 *trigger = NULL;
970 return 0;
971 }
972
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100973 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +0200974 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100975 const struct iio_device *cur = dev->ctx->devices[i];
976 if (cur->name && !strcmp(cur->name, buf)) {
977 *trigger = cur;
978 return 0;
979 }
980 }
981 return -ENXIO;
982}
983
984static int local_set_trigger(const struct iio_device *dev,
985 const struct iio_device *trigger)
986{
987 ssize_t nb;
988 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +0200989 nb = local_write_dev_attr(dev, "trigger/current_trigger",
990 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100991 if (nb < 0)
992 return (int) nb;
993 else
994 return 0;
995}
996
Lars-Peter Clausend9806c22016-01-26 16:35:42 +0100997static bool is_channel(const char *attr, bool strict)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100998{
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100999 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +01001000 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
1001 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001002 if (!strncmp(attr, "in_", 3))
1003 ptr = strchr(attr + 3, '_');
1004 else if (!strncmp(attr, "out_", 4))
1005 ptr = strchr(attr + 4, '_');
1006 if (!ptr)
1007 return false;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001008 if (!strict)
1009 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001010 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
1011 return true;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001012
Lars-Peter Clausen093ae462016-06-21 11:43:54 +02001013 if (find_channel_modifier(ptr + 1, NULL) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001014 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001015 return false;
1016}
1017
1018static char * get_channel_id(const char *attr)
1019{
1020 char *res, *ptr;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001021 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001022
1023 attr = strchr(attr, '_') + 1;
1024 ptr = strchr(attr, '_');
Lars-Peter Clausen093ae462016-06-21 11:43:54 +02001025 if (find_channel_modifier(ptr + 1, &len) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001026 ptr += len + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001027
1028 res = malloc(ptr - attr + 1);
1029 if (!res)
1030 return NULL;
1031
1032 memcpy(res, attr, ptr - attr);
1033 res[ptr - attr] = 0;
1034 return res;
1035}
1036
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001037static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001038{
1039 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001040 size_t len;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +02001041
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001042 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausen093ae462016-06-21 11:43:54 +02001043 if (find_channel_modifier(ptr, &len) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001044 ptr += len + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +02001045
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001046 if (chn->name) {
1047 size_t len = strlen(chn->name);
1048 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
1049 ptr += len + 1;
1050 }
1051
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001052 return iio_strdup(ptr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001053}
1054
1055static int read_device_name(struct iio_device *dev)
1056{
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001057 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +02001058 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +01001059 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001060 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +01001061 else if (ret == 0)
1062 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001063
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001064 dev->name = iio_strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001065 if (!dev->name)
1066 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +01001067 else
1068 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001069}
1070
1071static int add_attr_to_device(struct iio_device *dev, const char *attr)
1072{
Paul Cercueilbb618272014-02-20 11:35:52 +01001073 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001074 unsigned int i;
1075
1076 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
1077 if (!strcmp(device_attrs_blacklist[i], attr))
1078 return 0;
1079
1080 if (!strcmp(attr, "name"))
1081 return read_device_name(dev);
1082
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001083 name = iio_strdup(attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001084 if (!name)
1085 return -ENOMEM;
1086
1087 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
1088 if (!attrs) {
1089 free(name);
1090 return -ENOMEM;
1091 }
1092
1093 attrs[dev->nb_attrs++] = name;
1094 dev->attrs = attrs;
1095 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
1096 return 0;
1097}
1098
Paul Cercueila1a34c62016-08-09 12:53:39 +02001099static int handle_protected_scan_element_attr(struct iio_channel *chn,
1100 const char *name, const char *path)
1101{
1102 struct iio_device *dev = chn->dev;
1103 char buf[1024];
1104 int ret;
1105
1106 if (!strcmp(name, "index")) {
1107 ret = local_read_dev_attr(dev, path, buf, sizeof(buf), false);
1108 if (ret > 0)
1109 chn->index = atol(buf);
1110
1111 } else if (!strcmp(name, "type")) {
1112 ret = local_read_dev_attr(dev, path, buf, sizeof(buf), false);
1113 if (ret > 0) {
1114 char endian, sign;
1115
Lucas Magasweran77fe2912016-08-29 13:47:29 -07001116 if (strchr(buf, 'X')) {
1117 sscanf(buf, "%ce:%c%u/%uX%u>>%u", &endian, &sign,
1118 &chn->format.bits, &chn->format.length,
1119 &chn->format.repeat, &chn->format.shift);
1120 } else {
1121 chn->format.repeat = 1;
1122 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001123 &chn->format.bits, &chn->format.length,
1124 &chn->format.shift);
Lucas Magasweran77fe2912016-08-29 13:47:29 -07001125 }
Paul Cercueila1a34c62016-08-09 12:53:39 +02001126 chn->format.is_signed = (sign == 's' || sign == 'S');
1127 chn->format.is_fully_defined =
1128 (sign == 'S' || sign == 'U'||
1129 chn->format.bits == chn->format.length);
1130 chn->format.is_be = endian == 'b';
1131 }
1132
1133 } else if (!strcmp(name, "en")) {
1134 if (chn->pdata->enable_fn) {
1135 ERROR("Libiio bug: \"en\" attribute already parsed for channel %s!\n",
1136 chn->id);
1137 return -EINVAL;
1138 }
1139
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001140 chn->pdata->enable_fn = iio_strdup(path);
Paul Cercueila1a34c62016-08-09 12:53:39 +02001141 if (!chn->pdata->enable_fn)
1142 return -ENOMEM;
1143
1144 } else {
1145 return -EINVAL;
1146 }
1147
1148 return 0;
1149}
1150
Paul Cercueile3fbd952014-03-11 16:58:33 +01001151static int add_attr_to_channel(struct iio_channel *chn,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001152 const char *attr, const char *path, bool is_scan_element)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001153{
Paul Cercueilb34e0222014-05-05 15:32:38 +02001154 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001155 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001156 if (!name)
1157 return -ENOMEM;
1158
Paul Cercueila1a34c62016-08-09 12:53:39 +02001159 if (is_scan_element) {
1160 int ret = handle_protected_scan_element_attr(chn, name, path);
1161
1162 free(name);
1163 return ret;
1164 }
1165
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001166 fn = iio_strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +01001167 if (!fn)
1168 goto err_free_name;
1169
Paul Cercueilb34e0222014-05-05 15:32:38 +02001170 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
1171 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +01001172 if (!attrs)
1173 goto err_free_fn;
1174
Paul Cercueil42d12352014-05-05 16:11:58 +02001175 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +02001176 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001177 chn->attrs = attrs;
1178 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
1179 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +01001180
Paul Cercueil167d3112014-02-18 12:23:53 +01001181err_free_fn:
1182 free(fn);
1183err_free_name:
1184 free(name);
1185 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001186}
1187
1188static int add_channel_to_device(struct iio_device *dev,
1189 struct iio_channel *chn)
1190{
1191 struct iio_channel **channels = realloc(dev->channels,
1192 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
1193 if (!channels)
1194 return -ENOMEM;
1195
1196 channels[dev->nb_channels++] = chn;
1197 dev->channels = channels;
1198 DEBUG("Added channel \'%s\' to device \'%s\'\n", chn->id, dev->id);
1199 return 0;
1200}
1201
1202static int add_device_to_context(struct iio_context *ctx,
1203 struct iio_device *dev)
1204{
1205 struct iio_device **devices = realloc(ctx->devices,
1206 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
1207 if (!devices)
1208 return -ENOMEM;
1209
1210 devices[ctx->nb_devices++] = dev;
1211 ctx->devices = devices;
1212 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
1213 return 0;
1214}
1215
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001216static struct iio_channel *create_channel(struct iio_device *dev,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001217 char *id, const char *attr, const char *path,
1218 bool is_scan_element)
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001219{
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001220 struct iio_channel *chn = zalloc(sizeof(*chn));
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001221 if (!chn)
1222 return NULL;
1223
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001224 chn->pdata = zalloc(sizeof(*chn->pdata));
1225 if (!chn->pdata)
1226 goto err_free_chn;
1227
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001228 if (!strncmp(attr, "out_", 4))
1229 chn->is_output = true;
1230 else if (strncmp(attr, "in_", 3))
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001231 goto err_free_chn_pdata;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001232
1233 chn->dev = dev;
1234 chn->id = id;
Paul Cercueila1a34c62016-08-09 12:53:39 +02001235 chn->is_scan_element = is_scan_element;
1236 chn->index = -ENOENT;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001237
Paul Cercueila1a34c62016-08-09 12:53:39 +02001238 if (!add_attr_to_channel(chn, attr, path, is_scan_element))
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001239 return chn;
1240
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001241err_free_chn_pdata:
1242 free(chn->pdata->enable_fn);
1243 free(chn->pdata);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001244err_free_chn:
1245 free(chn);
1246 return NULL;
1247}
1248
1249static int add_channel(struct iio_device *dev, const char *name,
1250 const char *path, bool dir_is_scan_elements)
1251{
1252 struct iio_channel *chn;
1253 char *channel_id;
1254 unsigned int i;
1255 int ret;
1256
1257 channel_id = get_channel_id(name);
1258 if (!channel_id)
1259 return -ENOMEM;
1260
1261 for (i = 0; i < dev->nb_channels; i++) {
1262 chn = dev->channels[i];
1263 if (!strcmp(chn->id, channel_id)
1264 && chn->is_output == (name[0] == 'o')) {
1265 free(channel_id);
Paul Cercueila1a34c62016-08-09 12:53:39 +02001266 ret = add_attr_to_channel(chn, name, path,
1267 dir_is_scan_elements);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001268 chn->is_scan_element = dir_is_scan_elements && !ret;
1269 return ret;
1270 }
1271 }
1272
Paul Cercueila1a34c62016-08-09 12:53:39 +02001273 chn = create_channel(dev, channel_id, name, path, dir_is_scan_elements);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001274 if (!chn) {
1275 free(channel_id);
1276 return -ENXIO;
1277 }
Lars-Peter Clausenc6f85922016-04-20 15:03:49 +02001278
1279 iio_channel_init_finalize(chn);
1280
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001281 ret = add_channel_to_device(dev, chn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001282 if (ret) {
1283 free(chn->pdata->enable_fn);
1284 free(chn->pdata);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001285 free_channel(chn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001286 }
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001287 return ret;
1288}
1289
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001290/*
1291 * Possible return values:
1292 * 0 = Attribute should not be moved to the channel
1293 * 1 = Attribute should be moved to the channel and it is a shared attribute
1294 * 2 = Attribute should be moved to the channel and it is a private attribute
1295 */
1296static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001297{
Lars-Peter Clausen8ba0d5b2016-02-17 11:30:23 +01001298 unsigned int len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001299 char *ptr;
1300
Paul Cercueil35a01312014-02-20 10:56:57 +01001301 if (!chn->is_output && !strncmp(attr, "in_", 3))
1302 attr += 3;
1303 else if (chn->is_output && !strncmp(attr, "out_", 4))
1304 attr += 4;
1305 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001306 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001307
1308 ptr = strchr(attr, '_');
1309 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001310 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001311
1312 len = ptr - attr;
1313
1314 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001315 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001316
1317 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001318 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1319 if (chn->name) {
1320 size_t name_len = strlen(chn->name);
1321 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1322 attr[len + 1 + name_len] == '_')
1323 return 2;
1324 }
1325 return 1;
1326 } else if (chn->id[len] != '_') {
1327 return 0;
1328 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001329
Lars-Peter Clausen093ae462016-06-21 11:43:54 +02001330 if (find_channel_modifier(chn->id + len + 1, NULL) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001331 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001332
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001333 return 0;
1334}
1335
1336static int detect_global_attr(struct iio_device *dev, const char *attr,
1337 unsigned int level, bool *match)
1338{
1339 unsigned int i;
1340
1341 *match = false;
1342 for (i = 0; i < dev->nb_channels; i++) {
1343 struct iio_channel *chn = dev->channels[i];
1344 if (is_global_attr(chn, attr) == level) {
1345 int ret;
1346 *match = true;
Paul Cercueila1a34c62016-08-09 12:53:39 +02001347 ret = add_attr_to_channel(chn, attr, attr, false);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001348 if (ret)
1349 return ret;
1350 }
1351 }
1352
1353 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001354}
1355
1356static int detect_and_move_global_attrs(struct iio_device *dev)
1357{
1358 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001359 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001360
1361 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001362 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001363 bool match;
1364 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001365
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001366 ret = detect_global_attr(dev, attr, 2, &match);
1367 if (ret)
1368 return ret;
1369
1370 if (!match) {
1371 ret = detect_global_attr(dev, attr, 1, &match);
1372 if (ret)
1373 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001374 }
1375
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001376 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001377 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001378 dev->attrs[i] = NULL;
1379 }
1380 }
1381
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001382 /* Find channels without an index */
1383 for (i = 0; i < dev->nb_attrs; i++) {
1384 const char *attr = dev->attrs[i];
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001385 int ret;
1386
1387 if (!dev->attrs[i])
1388 continue;
1389
1390 if (is_channel(attr, false)) {
1391 ret = add_channel(dev, attr, attr, false);
1392 if (ret)
1393 return ret;
1394
1395 free(dev->attrs[i]);
1396 dev->attrs[i] = NULL;
1397 }
1398 }
1399
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001400 for (i = 0; i < dev->nb_attrs; i++) {
1401 if (dev->attrs[i])
1402 *ptr++ = dev->attrs[i];
1403 }
1404
1405 dev->nb_attrs = ptr - dev->attrs;
Lars-Peter Clausene8a2bb32016-04-12 18:43:31 +02001406 if (!dev->nb_attrs) {
1407 free(dev->attrs);
1408 dev->attrs = NULL;
1409 }
1410
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001411 return 0;
1412}
1413
Paul Cercueile3fbd952014-03-11 16:58:33 +01001414static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001415 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001416{
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001417 char buf[1024];
Paul Cercueil1be57832014-03-11 16:27:16 +01001418 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001419
1420 if (dir_is_scan_elements) {
1421 snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001422 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001423 } else {
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001424 if (!is_channel(name, true))
1425 return add_attr_to_device(dev, name);
Paul Cercueila91358e2014-04-24 16:40:19 +02001426 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001427 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001428
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001429 return add_channel(dev, name, path, dir_is_scan_elements);
Paul Cercueil1be57832014-03-11 16:27:16 +01001430}
1431
Paul Cercueile3fbd952014-03-11 16:58:33 +01001432static int add_attr_or_channel(void *d, const char *path)
1433{
Paul Cercueila91358e2014-04-24 16:40:19 +02001434 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001435}
1436
1437static int add_scan_element(void *d, const char *path)
1438{
Paul Cercueila91358e2014-04-24 16:40:19 +02001439 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001440}
1441
Paul Cercueil1be57832014-03-11 16:27:16 +01001442static int foreach_in_dir(void *d, const char *path, bool is_dir,
1443 int (*callback)(void *, const char *))
1444{
Paul Cercueil883204f2016-11-17 12:35:28 +01001445 struct dirent *entry;
1446 DIR *dir;
1447 int ret = 0;
1448
1449 dir = opendir(path);
Paul Cercueil1be57832014-03-11 16:27:16 +01001450 if (!dir)
1451 return -errno;
1452
Paul Cercueil1be57832014-03-11 16:27:16 +01001453 while (true) {
1454 struct stat st;
1455 char buf[1024];
Paul Cercueil883204f2016-11-17 12:35:28 +01001456
1457 errno = 0;
1458 entry = readdir(dir);
1459 if (!entry) {
1460 if (!errno)
1461 break;
1462
1463 ret = -errno;
1464 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001465 ERROR("Unable to open directory %s: %s\n", path, buf);
Paul Cercueil883204f2016-11-17 12:35:28 +01001466 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001467 }
Paul Cercueil1be57832014-03-11 16:27:16 +01001468
1469 snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
1470 if (stat(buf, &st) < 0) {
1471 ret = -errno;
Paul Cercueil87b988f2015-05-22 10:57:32 +02001472 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001473 ERROR("Unable to stat file: %s\n", buf);
Paul Cercueil883204f2016-11-17 12:35:28 +01001474 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001475 }
1476
1477 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1478 ret = callback(d, buf);
1479 else if (!is_dir && S_ISREG(st.st_mode))
1480 ret = callback(d, buf);
1481 else
1482 continue;
1483
Paul Cercueil883204f2016-11-17 12:35:28 +01001484 if (ret < 0)
1485 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001486 }
1487
Paul Cercueil883204f2016-11-17 12:35:28 +01001488out_close_dir:
Paul Cercueil1be57832014-03-11 16:27:16 +01001489 closedir(dir);
Paul Cercueil883204f2016-11-17 12:35:28 +01001490 return ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001491}
1492
Paul Cercueile3fbd952014-03-11 16:58:33 +01001493static int add_scan_elements(struct iio_device *dev, const char *devpath)
1494{
1495 struct stat st;
1496 char buf[1024];
1497 snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
1498
1499 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1500 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1501 if (ret < 0)
1502 return ret;
1503 }
1504
1505 return 0;
1506}
1507
Paul Cercueil1be57832014-03-11 16:27:16 +01001508static int create_device(void *d, const char *path)
1509{
Paul Cercueilff778232014-03-24 14:23:08 +01001510 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001511 unsigned int i;
1512 int ret;
1513 struct iio_context *ctx = d;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001514 struct iio_device *dev = zalloc(sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001515 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001516 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001517
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001518 dev->pdata = zalloc(sizeof(*dev->pdata));
Paul Cercueileaab6582014-02-21 09:35:59 +01001519 if (!dev->pdata) {
1520 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001521 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001522 }
1523
Romain Roffé6ce74a22015-06-30 11:45:11 +02001524 dev->pdata->fd = -1;
Romain Roffécead1da2015-06-30 13:35:51 +02001525 dev->pdata->blocking = true;
Romain Roffé0f737472015-06-30 16:45:54 +02001526 dev->pdata->nb_blocks = NB_BLOCKS;
Romain Roffé6ce74a22015-06-30 11:45:11 +02001527
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001528 dev->ctx = ctx;
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001529 dev->id = iio_strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001530 if (!dev->id) {
Romain Roffé0f737472015-06-30 16:45:54 +02001531 local_free_pdata(dev);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001532 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001533 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001534 }
1535
Paul Cercueil1be57832014-03-11 16:27:16 +01001536 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001537 if (ret < 0)
1538 goto err_free_device;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001539
Michael Hennerichebe49662014-11-07 10:32:44 +01001540 ret = add_scan_elements(dev, path);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001541 if (ret < 0)
1542 goto err_free_device;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001543
Paul Cercueilbab69a92015-07-03 11:24:17 +02001544 for (i = 0; i < dev->nb_channels; i++)
1545 set_channel_name(dev->channels[i]);
1546
Michael Hennerichebe49662014-11-07 10:32:44 +01001547 ret = detect_and_move_global_attrs(dev);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001548 if (ret < 0)
1549 goto err_free_device;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001550
Paul Cercueilff778232014-03-24 14:23:08 +01001551 dev->words = (dev->nb_channels + 31) / 32;
1552 if (dev->words) {
1553 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001554 if (!mask) {
Paul Cercueil290e0e02016-08-09 15:54:44 +02001555 ret = -ENOMEM;
1556 goto err_free_device;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001557 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001558 }
1559
Paul Cercueilff778232014-03-24 14:23:08 +01001560 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001561
Paul Cercueil1be57832014-03-11 16:27:16 +01001562 ret = add_device_to_context(ctx, dev);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001563 if (!ret)
1564 return 0;
1565
1566err_free_device:
1567 local_free_pdata(dev);
1568 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001569 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001570}
1571
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001572static int add_debug_attr(void *d, const char *path)
1573{
1574 struct iio_device *dev = d;
1575 const char *attr = strrchr(path, '/') + 1;
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001576 char **attrs, *name = iio_strdup(attr);
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001577 if (!name)
1578 return -ENOMEM;
1579
1580 attrs = realloc(dev->debug_attrs,
1581 (1 + dev->nb_debug_attrs) * sizeof(char *));
1582 if (!attrs) {
1583 free(name);
1584 return -ENOMEM;
1585 }
1586
1587 attrs[dev->nb_debug_attrs++] = name;
1588 dev->debug_attrs = attrs;
1589 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1590 return 0;
1591}
1592
1593static int add_debug(void *d, const char *path)
1594{
1595 struct iio_context *ctx = d;
1596 const char *name = strrchr(path, '/') + 1;
1597 struct iio_device *dev = iio_context_find_device(ctx, name);
1598 if (!dev)
1599 return -ENODEV;
1600 else
1601 return foreach_in_dir(dev, path, false, add_debug_attr);
1602}
1603
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001604static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1605{
Paul Cercueil00558f12016-04-12 14:40:40 +02001606 ctx->pdata->rw_timeout_ms = timeout;
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001607 return 0;
1608}
1609
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001610static void local_cancel(const struct iio_device *dev)
1611{
1612 struct iio_device_pdata *pdata = dev->pdata;
1613 uint64_t event = 1;
1614 int ret;
1615
1616 ret = write(pdata->cancel_fd, &event, sizeof(event));
1617 if (ret == -1) {
1618 /* If this happens something went very seriously wrong */
1619 char err_str[1024];
1620 iio_strerror(errno, err_str, sizeof(err_str));
1621 ERROR("Unable to signal cancellation event: %s\n", err_str);
1622 }
1623}
1624
Paul Cercueil0865e802014-10-28 14:35:19 +01001625static struct iio_context * local_clone(
1626 const struct iio_context *ctx __attribute__((unused)))
1627{
Paul Cercueil63e52182014-12-11 12:52:48 +01001628 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001629}
1630
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001631static const struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001632 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001633 .open = local_open,
1634 .close = local_close,
Romain Roffé87897862015-06-30 13:34:08 +02001635 .get_fd = local_get_fd,
Romain Roffécead1da2015-06-30 13:35:51 +02001636 .set_blocking_mode = local_set_blocking_mode,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001637 .read = local_read,
1638 .write = local_write,
Romain Roffé0f737472015-06-30 16:45:54 +02001639 .set_kernel_buffers_count = local_set_kernel_buffers_count,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001640 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001641 .read_device_attr = local_read_dev_attr,
1642 .write_device_attr = local_write_dev_attr,
1643 .read_channel_attr = local_read_chn_attr,
1644 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001645 .get_trigger = local_get_trigger,
1646 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001647 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001648 .set_timeout = local_set_timeout,
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001649 .cancel = local_cancel,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001650};
1651
Paul Cercueila1a34c62016-08-09 12:53:39 +02001652static void init_data_scale(struct iio_channel *chn)
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001653{
1654 char buf[1024];
1655 ssize_t ret;
1656
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001657 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1658 if (ret < 0) {
1659 chn->format.with_scale = false;
1660 } else {
1661 chn->format.with_scale = true;
1662 chn->format.scale = atof(buf);
1663 }
1664}
1665
1666static void init_scan_elements(struct iio_context *ctx)
1667{
1668 unsigned int i, j;
1669
1670 for (i = 0; i < ctx->nb_devices; i++) {
1671 struct iio_device *dev = ctx->devices[i];
1672
Paul Cercueila1a34c62016-08-09 12:53:39 +02001673 for (j = 0; j < dev->nb_channels; j++)
1674 init_data_scale(dev->channels[j]);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001675 }
1676}
1677
Paul Cercueile6be0702016-11-18 10:57:23 +01001678#ifdef WITH_LOCAL_CONFIG
1679static int populate_context_attrs(struct iio_context *ctx, const char *file)
1680{
1681 struct INI *ini;
1682 int ret;
1683
1684 ini = ini_open(file);
1685 if (!ini) {
1686 /* INI file not present -> not an error */
1687 if (errno == ENOENT)
1688 return 0;
1689 else
1690 return -errno;
1691 }
1692
1693 while (true) {
1694 const char *section;
1695 size_t len;
1696
1697 ret = ini_next_section(ini, &section, &len);
1698 if (ret <= 0)
1699 goto out_close_ini;
1700
1701 if (!strncmp(section, "Context Attributes", len))
1702 break;
1703 }
1704
1705 do {
1706 const char *key, *value;
1707 char *new_key, *new_val;
1708 size_t klen, vlen;
1709
1710 ret = ini_read_pair(ini, &key, &klen, &value, &vlen);
1711 if (ret <= 0)
1712 break;
1713
1714 /* Create a dup of the strings read from the INI, since they are
1715 * not NULL-terminated. */
1716 new_key = strndup(key, klen);
1717 new_val = strndup(value, vlen);
1718
1719 if (!new_key || !new_val)
1720 ret = -ENOMEM;
1721 else
1722 ret = iio_context_add_attr(ctx, new_key, new_val);
1723
1724 free(new_key);
1725 free(new_val);
1726 } while (!ret);
1727
1728out_close_ini:
1729 ini_close(ini);
1730 return ret;
1731}
1732#endif
1733
Paul Cercueil63e52182014-12-11 12:52:48 +01001734struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001735{
Paul Cercueilfd387472015-08-05 10:34:19 +02001736 int ret = -ENOMEM;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001737 unsigned int len;
1738 struct utsname uts;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001739 struct iio_context *ctx = zalloc(sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001740 if (!ctx)
Paul Cercueilfd387472015-08-05 10:34:19 +02001741 goto err_set_errno;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001742
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001743 ctx->ops = &local_ops;
1744 ctx->name = "local";
Paul Cercueil00558f12016-04-12 14:40:40 +02001745
1746 ctx->pdata = zalloc(sizeof(*ctx->pdata));
1747 if (!ctx->pdata) {
1748 free(ctx);
1749 goto err_set_errno;
1750 }
1751
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001752 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001753
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001754 uname(&uts);
1755 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
1756 + strlen(uts.version) + strlen(uts.machine);
1757 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
1758 if (!ctx->description) {
Paul Cercueil00558f12016-04-12 14:40:40 +02001759 free(ctx->pdata);
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001760 free(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001761 goto err_set_errno;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001762 }
1763
1764 snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
1765 uts.nodename, uts.release, uts.version, uts.machine);
1766
Paul Cercueil1be57832014-03-11 16:27:16 +01001767 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
Paul Cercueilfd387472015-08-05 10:34:19 +02001768 if (ret < 0)
1769 goto err_context_destroy;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001770
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001771 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001772
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001773 init_scan_elements(ctx);
Paul Cercueile6be0702016-11-18 10:57:23 +01001774
1775#ifdef WITH_LOCAL_CONFIG
1776 ret = populate_context_attrs(ctx, "/etc/libiio.ini");
1777 if (ret < 0)
1778 goto err_context_destroy;
1779#endif
1780
Paul Cercueilfd387472015-08-05 10:34:19 +02001781 ret = iio_context_init(ctx);
1782 if (ret < 0)
1783 goto err_context_destroy;
Paul Cercueilae88fde2014-03-12 11:47:10 +01001784
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001785 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001786
Paul Cercueilfd387472015-08-05 10:34:19 +02001787err_context_destroy:
1788 iio_context_destroy(ctx);
1789err_set_errno:
1790 errno = -ret;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001791 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001792}
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001793
1794static int check_device(void *d, const char *path)
1795{
1796 *(bool *)d = true;
1797 return 0;
1798}
1799
1800int local_context_scan(struct iio_scan_result *scan_result)
1801{
1802 struct iio_context_info **info;
1803 bool exists = false;
Paul Cercueil6303ca22016-11-10 16:55:40 +01001804 char *desc, *uri;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001805 int ret;
1806
1807 ret = foreach_in_dir(&exists, "/sys/bus/iio/devices",
1808 true, check_device);
1809 if (ret < 0 || !exists)
1810 return 0;
1811
Paul Cercueil6303ca22016-11-10 16:55:40 +01001812 desc = iio_strdup("Local devices");
1813 if (!desc)
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001814 return -ENOMEM;
1815
Paul Cercueil6303ca22016-11-10 16:55:40 +01001816 uri = iio_strdup("local:");
1817 if (!uri)
1818 goto err_free_desc;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001819
Paul Cercueil6303ca22016-11-10 16:55:40 +01001820 info = iio_scan_result_add(scan_result, 1);
1821 if (!info)
1822 goto err_free_uri;
1823
1824 info[0]->description = desc;
1825 info[0]->uri = uri;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001826 return 0;
Paul Cercueil6303ca22016-11-10 16:55:40 +01001827
1828err_free_uri:
1829 free(uri);
1830err_free_desc:
1831 free(desc);
1832 return -ENOMEM;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001833}