blob: b5e387c5cfbdf1a0350f5ef5f096ca75def8b28c [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>
Lars-Peter Clausenea5ea6f2016-04-21 18:23:38 +020025#include <limits.h>
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020026#include <poll.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010027#include <stdbool.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010028#include <stddef.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010029#include <stdio.h>
30#include <string.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>
Romain Roffécead1da2015-06-30 13:35:51 +020038#include <unistd.h>
Romain Roffé6ce74a22015-06-30 11:45:11 +020039#include <fcntl.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010040
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020041#define DEFAULT_TIMEOUT_MS 1000
42
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 Cercueil00558f12016-04-12 14:40:40 +020080struct iio_context_pdata {
81 unsigned long rw_timeout_ms;
82};
83
Paul Cercueileaab6582014-02-21 09:35:59 +010084struct iio_device_pdata {
Romain Roffé6ce74a22015-06-30 11:45:11 +020085 int fd;
Romain Roffécead1da2015-06-30 13:35:51 +020086 bool blocking;
Paul Cercueil71694c72014-05-22 14:02:13 +020087 unsigned int samples_count, nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +020088
Romain Roffé0f737472015-06-30 16:45:54 +020089 struct block *blocks;
90 void **addrs;
Paul Cercueil92f46df2014-04-28 13:17:53 +020091 int last_dequeued;
Paul Cercueil6ea8a752014-06-03 11:35:35 +020092 bool is_high_speed, cyclic, cyclic_buffer_enqueued, buffer_enabled;
Paul Cercueileaab6582014-02-21 09:35:59 +010093};
94
Paul Cercueil0b2ce712014-02-17 15:04:18 +010095static const char * const device_attrs_blacklist[] = {
96 "dev",
97 "uevent",
98};
99
100static const char * const modifier_names[] = {
101 [IIO_MOD_X] = "x",
102 [IIO_MOD_Y] = "y",
103 [IIO_MOD_Z] = "z",
104 [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)",
105 [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
106 [IIO_MOD_LIGHT_BOTH] = "both",
107 [IIO_MOD_LIGHT_IR] = "ir",
108 [IIO_MOD_LIGHT_CLEAR] = "clear",
109 [IIO_MOD_LIGHT_RED] = "red",
110 [IIO_MOD_LIGHT_GREEN] = "green",
111 [IIO_MOD_LIGHT_BLUE] = "blue",
Lars-Peter Clausen9958dda2016-04-20 13:23:07 +0200112 [IIO_MOD_QUATERNION] = "quaternion",
113 [IIO_MOD_TEMP_AMBIENT] = "ambient",
114 [IIO_MOD_TEMP_OBJECT] = "object",
115 [IIO_MOD_NORTH_MAGN] = "from_north_magnetic",
116 [IIO_MOD_NORTH_TRUE] = "from_north_true",
117 [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
118 [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
119 [IIO_MOD_RUNNING] = "running",
120 [IIO_MOD_JOGGING] = "jogging",
121 [IIO_MOD_WALKING] = "walking",
122 [IIO_MOD_STILL] = "still",
123 [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
Lars-Peter Clausen60aa4042015-03-27 13:34:55 +0100124 [IIO_MOD_I] = "i",
125 [IIO_MOD_Q] = "q",
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100126};
127
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100128/*
129 * Looks for a IIO channel modifier at the beginning of the string s. If a
130 * modifier was found the symbolic constant (IIO_MOD_*) is returned, otherwise
131 * IIO_NO_MOD is returned. If a modifier was found len_p will be update with the
132 * length of the modifier.
133 */
134static unsigned int find_modifier(const char *s, size_t *len_p)
135{
136 unsigned int i;
137 size_t len;
138
139 for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
140 if (!modifier_names[i])
141 continue;
142 len = strlen(modifier_names[i]);
Paul Cercueil23efdd82015-08-05 11:02:28 +0200143 if (strncmp(s, modifier_names[i], len) == 0 &&
144 (s[len] == '\0' || s[len] == '_')) {
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100145 if (len_p)
146 *len_p = len;
147 return i;
148 }
149 }
150
151 return IIO_NO_MOD;
152}
153
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200154static int ioctl_nointr(int fd, unsigned long request, void *data)
155{
156 int ret;
157
158 do {
159 ret = ioctl(fd, request, data);
160 } while (ret == -1 && errno == EINTR);
161
162 return ret;
163}
164
Romain Roffé0f737472015-06-30 16:45:54 +0200165static void local_free_pdata(struct iio_device *device)
166{
167 if (device && device->pdata) {
168 free(device->pdata->blocks);
169 free(device->pdata->addrs);
170 free(device->pdata);
171 }
172}
173
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100174static void local_shutdown(struct iio_context *ctx)
175{
Paul Cercueil42d12352014-05-05 16:11:58 +0200176 /* Free the backend data stored in every device structure */
Paul Cercueil167d3112014-02-18 12:23:53 +0100177 unsigned int i;
Paul Cercueil00558f12016-04-12 14:40:40 +0200178
179 for (i = 0; i < ctx->nb_devices; i++)
Romain Roffé0f737472015-06-30 16:45:54 +0200180 local_free_pdata(ctx->devices[i]);
Paul Cercueil00558f12016-04-12 14:40:40 +0200181
182 free(ctx->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100183}
184
Michael Hennerich1c8aa572014-11-06 17:42:30 +0100185/** Shrinks the first nb characters of a string
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100186 * e.g. strcut("foobar", 4) replaces the content with "ar". */
187static void strcut(char *str, int nb)
188{
189 char *ptr = str + nb;
190 while (*ptr)
191 *str++ = *ptr++;
192 *str = 0;
193}
194
195static int set_channel_name(struct iio_channel *chn)
196{
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100197 size_t prefix_len = 0;
198 const char *attr0;
199 const char *ptr;
200 unsigned int i;
201
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100202 if (chn->nb_attrs < 2)
203 return 0;
204
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100205 attr0 = ptr = chn->attrs[0].name;
206
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100207 while (true) {
208 bool can_fix = true;
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100209 size_t len;
210
211 ptr = strchr(ptr, '_');
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100212 if (!ptr)
213 break;
214
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100215 len = ptr - attr0 + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100216 for (i = 1; can_fix && i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200217 can_fix = !strncmp(attr0, chn->attrs[i].name, len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100218
219 if (!can_fix)
220 break;
221
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100222 prefix_len = len;
223 ptr = ptr + 1;
224 }
225
226 if (prefix_len) {
227 char *name;
228
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100229 name = malloc(prefix_len);
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100230 if (!name)
231 return -ENOMEM;
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100232 strncpy(name, attr0, prefix_len - 1);
233 name[prefix_len - 1] = '\0';
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100234 DEBUG("Setting name of channel %s to %s\n", chn->id, name);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100235 chn->name = name;
236
237 /* Shrink the attribute name */
238 for (i = 0; i < chn->nb_attrs; i++)
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100239 strcut(chn->attrs[i].name, prefix_len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100240 }
241
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100242 return 0;
243}
244
Paul Cercueil3dad0482016-02-04 11:40:32 +0100245static int device_check_ready(const struct iio_device *dev, short events)
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200246{
247 struct pollfd pollfd = {
Romain Roffé6ce74a22015-06-30 11:45:11 +0200248 .fd = dev->pdata->fd,
Paul Cercueil3dad0482016-02-04 11:40:32 +0100249 .events = events,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200250 };
Lars-Peter Clausenea5ea6f2016-04-21 18:23:38 +0200251 unsigned long rw_timeout_ms = dev->ctx->pdata->rw_timeout_ms;
252 int poll_timeout;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200253 int ret;
254
Romain Roffécead1da2015-06-30 13:35:51 +0200255 if (!dev->pdata->blocking)
256 return 0;
257
Lars-Peter Clausenea5ea6f2016-04-21 18:23:38 +0200258 if (rw_timeout_ms == 0)
259 poll_timeout = -1;
260 else if (rw_timeout_ms > INT_MAX)
261 poll_timeout = INT_MAX;
262 else
263 poll_timeout = (int) rw_timeout_ms;
264
265 ret = poll(&pollfd, 1, poll_timeout);
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200266 if (ret < 0)
267 return -errno;
268 if (!ret)
269 return -ETIMEDOUT;
270 if (pollfd.revents & POLLNVAL)
271 return -EBADF;
Paul Cercueil3dad0482016-02-04 11:40:32 +0100272 if (!(pollfd.revents & events))
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200273 return -EIO;
274 return 0;
275}
276
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200277static ssize_t local_read(const struct iio_device *dev,
278 void *dst, size_t len, uint32_t *mask, size_t words)
Romain Roffé6ce74a22015-06-30 11:45:11 +0200279{
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200280 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200281 uintptr_t ptr = (uintptr_t) dst;
282 ssize_t readsize;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200283 ssize_t ret;
284
285 if (pdata->fd == -1)
286 return -EBADF;
287 if (words != dev->words)
288 return -EINVAL;
289
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200290 memcpy(mask, dev->mask, words);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200291
Lars-Peter Clausen8ba0d5b2016-02-17 11:30:23 +0100292 if (len == 0)
293 return 0;
294
Lars-Peter Clausen525c93e2016-04-21 14:05:27 +0200295 ret = device_check_ready(dev, POLLIN);
296 if (ret < 0)
297 return ret;
298
Romain Roffé6ce74a22015-06-30 11:45:11 +0200299 while (len > 0) {
300 do {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200301 ret = read(pdata->fd, (void *) ptr, len);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200302 } while (ret == -1 && errno == EINTR);
303
304 if (ret == -1) {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200305 ret = -EIO;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200306 break;
307 } else if (ret == 0) {
308 ret = -EIO;
309 break;
310 }
311
312 ptr += ret;
313 len -= ret;
314 }
315
316 readsize = (ssize_t)(ptr - (uintptr_t) dst);
Romain Roffécead1da2015-06-30 13:35:51 +0200317 if ((ret > 0 || ret == -EAGAIN) && (readsize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200318 return readsize;
319 else
320 return ret;
321}
322
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200323static ssize_t local_write(const struct iio_device *dev,
324 const void *src, size_t len)
Romain Roffé6ce74a22015-06-30 11:45:11 +0200325{
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200326 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200327 uintptr_t ptr = (uintptr_t) src;
328 ssize_t writtensize;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200329 ssize_t ret;
330
331 if (pdata->fd == -1)
332 return -EBADF;
333
Lars-Peter Clausen525c93e2016-04-21 14:05:27 +0200334 if (len == 0)
335 return 0;
336
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200337 ret = device_check_ready(dev, POLLOUT);
338 if (ret < 0)
339 return ret;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200340
341 while (len > 0) {
342 do {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200343 ret = write(pdata->fd, (void *) ptr, len);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200344 } while (ret == -1 && errno == EINTR);
345
346 if (ret == -1) {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200347 ret = -EIO;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200348 break;
349 } else if (ret == 0) {
350 ret = -EIO;
351 break;
352 }
353
354 ptr += ret;
355 len -= ret;
356 }
357
358 writtensize = (ssize_t)(ptr - (uintptr_t) src);
Romain Roffécead1da2015-06-30 13:35:51 +0200359 if ((ret > 0 || ret == -EAGAIN) && (writtensize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200360 return writtensize;
361 else
362 return ret;
363}
364
Romain Roffécead1da2015-06-30 13:35:51 +0200365static ssize_t local_enable_buffer(const struct iio_device *dev)
366{
367 struct iio_device_pdata *pdata = dev->pdata;
368 ssize_t ret = 0;
369
370 if (!pdata->buffer_enabled) {
371 ret = local_write_dev_attr(dev,
372 "buffer/enable", "1", 2, false);
373 if (ret >= 0)
374 pdata->buffer_enabled = true;
375 }
376
377 return 0;
378}
Romain Roffé6ce74a22015-06-30 11:45:11 +0200379
Romain Roffé0f737472015-06-30 16:45:54 +0200380static int local_set_kernel_buffers_count(const struct iio_device *dev,
381 unsigned int nb_blocks)
382{
383 struct iio_device_pdata *pdata = dev->pdata;
384
385 if (pdata->fd != -1)
386 return -EBUSY;
387
388 pdata->nb_blocks = nb_blocks;
389
390 return 0;
391}
392
Paul Cercueil92f46df2014-04-28 13:17:53 +0200393static ssize_t local_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100394 void **addr_ptr, size_t bytes_used,
395 uint32_t *mask, size_t words)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200396{
397 struct block block;
398 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200399 char err_str[1024];
Romain Roffé6ce74a22015-06-30 11:45:11 +0200400 int f = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200401 ssize_t ret;
402
403 if (!pdata->is_high_speed)
404 return -ENOSYS;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200405 if (f == -1)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200406 return -EBADF;
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200407 if (!addr_ptr)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200408 return -EINVAL;
409
Paul Cercueil92f46df2014-04-28 13:17:53 +0200410 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200411 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200412
413 if (pdata->cyclic) {
414 if (pdata->cyclic_buffer_enqueued)
415 return -EBUSY;
416 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
417 pdata->cyclic_buffer_enqueued = true;
418 }
419
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200420 last_block->bytes_used = bytes_used;
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200421 ret = (ssize_t) ioctl_nointr(f,
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200422 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200423 if (ret) {
424 ret = (ssize_t) -errno;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200425 iio_strerror(errno, err_str, sizeof(err_str));
426 ERROR("Unable to enqueue block: %s\n", err_str);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200427 return ret;
428 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200429
430 if (pdata->cyclic) {
431 *addr_ptr = pdata->addrs[pdata->last_dequeued];
432 return (ssize_t) last_block->bytes_used;
433 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200434 }
435
Lars-Peter Clausene63811e2016-04-21 11:22:33 +0200436 ret = (ssize_t) device_check_ready(dev, POLLIN | POLLOUT);
437 if (ret < 0)
438 return ret;
439
Nicholas Pillitteric65095d2015-05-18 20:11:47 -0400440 memset(&block, 0, sizeof(block));
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200441 ret = (ssize_t) ioctl_nointr(f, BLOCK_DEQUEUE_IOCTL, &block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200442 if (ret) {
443 ret = (ssize_t) -errno;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200444 iio_strerror(errno, err_str, sizeof(err_str));
445 ERROR("Unable to dequeue block: %s\n", err_str);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200446 return ret;
447 }
448
Paul Cercueil558ade42014-11-27 10:59:48 +0100449 /* Requested buffer size is too big! */
450 if (pdata->last_dequeued < 0 && bytes_used != block.size)
451 return -EFBIG;
452
Paul Cercueil92f46df2014-04-28 13:17:53 +0200453 pdata->last_dequeued = block.id;
454 *addr_ptr = pdata->addrs[block.id];
455 return (ssize_t) block.bytes_used;
456}
457
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200458static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
459 char *dst, size_t len, bool is_debug)
460{
461 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
462 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
463 char *ptr = dst;
464
465 for (i = 0; len >= 4 && i < nb; i++) {
466 /* Recursive! */
467 ssize_t ret = local_read_dev_attr(dev, attrs[i],
468 ptr + 4, len - 4, is_debug);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200469 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200470
471 /* Align the length to 4 bytes */
472 if (ret > 0 && ret & 3)
473 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200474 ptr += 4 + (ret < 0 ? 0 : ret);
475 len -= 4 + (ret < 0 ? 0 : ret);
476 }
477
478 return ptr - dst;
479}
480
481static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
482 char *dst, size_t len)
483{
484 unsigned int i;
485 char *ptr = dst;
486
487 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
488 /* Recursive! */
489 ssize_t ret = local_read_chn_attr(chn,
490 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200491 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200492
493 /* Align the length to 4 bytes */
494 if (ret > 0 && ret & 3)
495 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200496 ptr += 4 + (ret < 0 ? 0 : ret);
497 len -= 4 + (ret < 0 ? 0 : ret);
498 }
499
500 return ptr - dst;
501}
502
Paul Cercueil1da28122014-05-22 10:59:49 +0200503static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
504{
505 while (nb--) {
506 int32_t val;
507
508 if (len < 4)
509 return -EINVAL;
510
511 val = (int32_t) ntohl(*(uint32_t *) src);
512 src += 4;
513 len -= 4;
514
515 if (val > 0) {
516 if ((uint32_t) val > len)
517 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200518
519 /* Align the length to 4 bytes */
520 if (val & 3)
521 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200522 len -= val;
523 src += val;
524 }
525 }
526
527 /* We should have analyzed the whole buffer by now */
528 return !len ? 0 : -EINVAL;
529}
530
531static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
532 const char *src, size_t len, bool is_debug)
533{
534 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
535 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
536 const char *ptr = src;
537
538 /* First step: Verify that the buffer is in the correct format */
539 if (local_buffer_analyze(nb, src, len))
540 return -EINVAL;
541
542 /* Second step: write the attributes */
543 for (i = 0; i < nb; i++) {
544 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
545 ptr += 4;
546
547 if (val > 0) {
548 local_write_dev_attr(dev, attrs[i], ptr, val, is_debug);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200549
550 /* Align the length to 4 bytes */
551 if (val & 3)
552 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200553 ptr += val;
554 }
555 }
556
557 return ptr - src;
558}
559
560static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
561 const char *src, size_t len)
562{
563 unsigned int i, nb = chn->nb_attrs;
564 const char *ptr = src;
565
566 /* First step: Verify that the buffer is in the correct format */
567 if (local_buffer_analyze(nb, src, len))
568 return -EINVAL;
569
570 /* Second step: write the attributes */
571 for (i = 0; i < nb; i++) {
572 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
573 ptr += 4;
574
575 if (val > 0) {
576 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200577
578 /* Align the length to 4 bytes */
579 if (val & 3)
580 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200581 ptr += val;
582 }
583 }
584
585 return ptr - src;
586}
587
Paul Cercueil167d3112014-02-18 12:23:53 +0100588static ssize_t local_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200589 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100590{
Paul Cercueil3e898302014-02-17 16:17:11 +0100591 FILE *f;
592 char buf[1024];
593 ssize_t ret;
594
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200595 if (!attr)
596 return local_read_all_dev_attrs(dev, dst, len, is_debug);
597
Paul Cercueil50c762a2014-04-14 15:55:43 +0200598 if (is_debug)
599 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
600 dev->id, attr);
601 else
602 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
603 dev->id, attr);
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100604 f = fopen(buf, "re");
Paul Cercueil3e898302014-02-17 16:17:11 +0100605 if (!f)
606 return -errno;
607
608 ret = fread(dst, 1, len, f);
609 if (ret > 0)
610 dst[ret - 1] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100611 fflush(f);
612 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200613 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100614 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200615 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100616}
617
Paul Cercueil167d3112014-02-18 12:23:53 +0100618static ssize_t local_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200619 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100620{
Paul Cercueil3e898302014-02-17 16:17:11 +0100621 FILE *f;
622 char buf[1024];
623 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100624
Paul Cercueil1da28122014-05-22 10:59:49 +0200625 if (!attr)
626 return local_write_all_dev_attrs(dev, src, len, is_debug);
627
Paul Cercueil50c762a2014-04-14 15:55:43 +0200628 if (is_debug)
629 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
630 dev->id, attr);
631 else
632 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
633 dev->id, attr);
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100634 f = fopen(buf, "we");
Paul Cercueil3e898302014-02-17 16:17:11 +0100635 if (!f)
636 return -errno;
637
638 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100639 fflush(f);
640 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200641 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100642 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200643 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100644}
645
Paul Cercueil167d3112014-02-18 12:23:53 +0100646static const char * get_filename(const struct iio_channel *chn,
647 const char *attr)
648{
Paul Cercueil167d3112014-02-18 12:23:53 +0100649 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200650 for (i = 0; i < chn->nb_attrs; i++)
651 if (!strcmp(attr, chn->attrs[i].name))
652 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100653 return attr;
654}
655
656static ssize_t local_read_chn_attr(const struct iio_channel *chn,
657 const char *attr, char *dst, size_t len)
658{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200659 if (!attr)
660 return local_read_all_chn_attrs(chn, dst, len);
661
Paul Cercueil167d3112014-02-18 12:23:53 +0100662 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200663 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100664}
665
666static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200667 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100668{
Paul Cercueil1da28122014-05-22 10:59:49 +0200669 if (!attr)
670 return local_write_all_chn_attrs(chn, src, len);
671
Paul Cercueil167d3112014-02-18 12:23:53 +0100672 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200673 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100674}
675
Paul Cercueilff778232014-03-24 14:23:08 +0100676static int channel_write_state(const struct iio_channel *chn)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100677{
Paul Cercueilff778232014-03-24 14:23:08 +0100678 char *en = iio_channel_is_enabled(chn) ? "1" : "0";
Paul Cercueilcecda352014-05-06 18:14:29 +0200679 ssize_t ret = local_write_chn_attr(chn, "en", en, 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100680 if (ret < 0)
681 return (int) ret;
682 else
683 return 0;
684}
685
Paul Cercueil92f46df2014-04-28 13:17:53 +0200686static int enable_high_speed(const struct iio_device *dev)
687{
688 struct block_alloc_req req;
689 struct iio_device_pdata *pdata = dev->pdata;
690 unsigned int i;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200691 int ret, fd = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200692
Paul Cercueil71694c72014-05-22 14:02:13 +0200693 if (pdata->cyclic) {
694 pdata->nb_blocks = 1;
695 DEBUG("Enabling cyclic mode\n");
696 } else {
Paul Cercueil71694c72014-05-22 14:02:13 +0200697 DEBUG("Cyclic mode not enabled\n");
698 }
699
Romain Roffé0f737472015-06-30 16:45:54 +0200700 pdata->blocks = calloc(pdata->nb_blocks, sizeof(*pdata->blocks));
701 if (!pdata->blocks) {
702 pdata->nb_blocks = 0;
703 return -ENOMEM;
704 }
705
706 pdata->addrs = calloc(pdata->nb_blocks, sizeof(*pdata->addrs));
707 if (!pdata->addrs) {
708 free(pdata->blocks);
709 pdata->blocks = NULL;
710 return -ENOMEM;
711 }
712
Paul Cercueil1fa913d2015-04-28 16:30:53 +0200713 req.id = 0;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200714 req.type = 0;
715 req.size = pdata->samples_count *
716 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Paul Cercueil71694c72014-05-22 14:02:13 +0200717 req.count = pdata->nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200718
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200719 ret = ioctl_nointr(fd, BLOCK_ALLOC_IOCTL, &req);
Romain Roffé0f737472015-06-30 16:45:54 +0200720 if (ret < 0) {
721 ret = -errno;
722 goto err_freemem;
723 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200724
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200725 /* We might get less blocks than what we asked for */
726 pdata->nb_blocks = req.count;
727
Paul Cercueil92f46df2014-04-28 13:17:53 +0200728 /* mmap all the blocks */
Paul Cercueil71694c72014-05-22 14:02:13 +0200729 for (i = 0; i < pdata->nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200730 pdata->blocks[i].id = i;
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200731 ret = ioctl_nointr(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200732 if (ret) {
733 ret = -errno;
734 goto err_munmap;
735 }
736
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200737 ret = ioctl_nointr(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200738 if (ret) {
739 ret = -errno;
740 goto err_munmap;
741 }
742
Paul Cercueil032a5652014-05-12 17:11:19 +0200743 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
744 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200745 MAP_SHARED, fd, pdata->blocks[i].offset);
746 if (pdata->addrs[i] == MAP_FAILED) {
747 ret = -errno;
748 goto err_munmap;
749 }
750 }
751
Paul Cercueil4a702d32014-05-12 17:02:37 +0200752 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200753 return 0;
754
755err_munmap:
756 for (; i > 0; i--)
757 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200758 ioctl_nointr(fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200759err_freemem:
760 free(pdata->addrs);
761 pdata->addrs = NULL;
762 free(pdata->blocks);
763 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200764 return ret;
765}
766
Paul Cercueil92f15c22015-04-20 11:36:51 +0200767static int local_open(const struct iio_device *dev,
768 size_t samples_count, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100769{
770 unsigned int i;
771 int ret;
772 char buf[1024];
773 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200774
Romain Roffé6ce74a22015-06-30 11:45:11 +0200775 if (pdata->fd != -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100776 return -EBUSY;
777
Paul Cercueilcecda352014-05-06 18:14:29 +0200778 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200779 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100780 return ret;
781
Paul Cercueil11334342015-06-23 16:55:35 +0200782 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200783 ret = local_write_dev_attr(dev, "buffer/length",
784 buf, strlen(buf) + 1, false);
785 if (ret < 0)
786 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200787
Paul Cercueil8c29e412014-04-07 09:46:45 +0200788 snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100789 pdata->fd = open(buf, O_RDWR | O_CLOEXEC);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200790 if (pdata->fd == -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100791 return -errno;
792
Paul Cercueil11334342015-06-23 16:55:35 +0200793 /* Disable channels */
794 for (i = 0; i < dev->nb_channels; i++) {
795 struct iio_channel *chn = dev->channels[i];
796 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
797 ret = channel_write_state(chn);
798 if (ret < 0)
799 goto err_close;
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100800 }
Paul Cercueil11334342015-06-23 16:55:35 +0200801 }
802 /* Enable channels */
803 for (i = 0; i < dev->nb_channels; i++) {
804 struct iio_channel *chn = dev->channels[i];
805 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
806 ret = channel_write_state(chn);
807 if (ret < 0)
808 goto err_close;
Paul Cercueile1311222014-03-12 15:46:16 +0100809 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100810 }
811
Paul Cercueil71694c72014-05-22 14:02:13 +0200812 pdata->cyclic = cyclic;
813 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200814 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200815 pdata->samples_count = samples_count;
Paul Cercueil71694c72014-05-22 14:02:13 +0200816 pdata->is_high_speed = !enable_high_speed(dev);
Paul Cercueilb762fc62014-05-12 16:56:09 +0200817
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200818 if (!pdata->is_high_speed) {
Romain Roffé0f737472015-06-30 16:45:54 +0200819 unsigned long size = samples_count * pdata->nb_blocks;
Paul Cercueil032a5652014-05-12 17:11:19 +0200820 WARNING("High-speed mode not enabled\n");
Paul Cercueiled621ee2015-06-24 10:50:21 +0200821
Lars-Peter Clausen23804792016-04-20 18:17:56 +0200822 /* Cyclic mode is only supported in high-speed mode */
823 if (cyclic)
824 return -EPERM;
825
Paul Cercueiled621ee2015-06-24 10:50:21 +0200826 /* Increase the size of the kernel buffer, when using the
827 * low-speed interface. This avoids losing samples when
828 * refilling the iio_buffer. */
Romain Roffé0f737472015-06-30 16:45:54 +0200829 snprintf(buf, sizeof(buf), "%lu", size);
Paul Cercueiled621ee2015-06-24 10:50:21 +0200830 ret = local_write_dev_attr(dev, "buffer/length",
831 buf, strlen(buf) + 1, false);
832 if (ret < 0)
833 goto err_close;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200834 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100835
Lars-Peter Clausen53d6d452016-04-20 17:46:11 +0200836 ret = local_enable_buffer(dev);
837 if (ret < 0)
838 goto err_close;
839
Paul Cercueil45c575d2014-03-20 15:14:01 +0100840 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +0100841err_close:
Romain Roffé6ce74a22015-06-30 11:45:11 +0200842 close(pdata->fd);
843 pdata->fd = -1;
Paul Cercueile1311222014-03-12 15:46:16 +0100844 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100845}
846
847static int local_close(const struct iio_device *dev)
848{
849 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100850 int ret;
851
Paul Cercueilb6a40c22015-07-02 11:12:16 +0200852 if (pdata->fd == -1)
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100853 return -EBADF;
854
Paul Cercueil92f46df2014-04-28 13:17:53 +0200855 if (pdata->is_high_speed) {
856 unsigned int i;
Paul Cercueil71694c72014-05-22 14:02:13 +0200857 for (i = 0; i < pdata->nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200858 munmap(pdata->addrs[i], pdata->blocks[i].size);
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200859 ioctl_nointr(pdata->fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200860 free(pdata->addrs);
861 pdata->addrs = NULL;
862 free(pdata->blocks);
863 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200864 }
865
Romain Roffé6ce74a22015-06-30 11:45:11 +0200866 ret = close(pdata->fd);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100867 if (ret)
868 return ret;
869
Romain Roffé6ce74a22015-06-30 11:45:11 +0200870 pdata->fd = -1;
Paul Cercueil71694c72014-05-22 14:02:13 +0200871 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
872 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100873}
874
Romain Roffé87897862015-06-30 13:34:08 +0200875static int local_get_fd(const struct iio_device *dev)
876{
Paul Cercueil2cdc81b2015-07-02 11:13:23 +0200877 if (dev->pdata->fd == -1)
878 return -EBADF;
879 else
880 return dev->pdata->fd;
Romain Roffé87897862015-06-30 13:34:08 +0200881}
882
Romain Roffécead1da2015-06-30 13:35:51 +0200883static int local_set_blocking_mode(const struct iio_device *dev, bool blocking)
884{
885 int ret;
886
887 if (dev->pdata->fd == -1)
888 return -EBADF;
889
890 if (dev->pdata->cyclic)
891 return -EPERM;
892
893 ret = set_blocking_mode(dev->pdata->fd, blocking);
Lars-Peter Clausen53d6d452016-04-20 17:46:11 +0200894 if (ret == 0)
Romain Roffécead1da2015-06-30 13:35:51 +0200895 dev->pdata->blocking = blocking;
896
Romain Roffécead1da2015-06-30 13:35:51 +0200897 return ret;
898}
899
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100900static int local_get_trigger(const struct iio_device *dev,
901 const struct iio_device **trigger)
902{
903 char buf[1024];
904 unsigned int i;
905 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +0200906 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +0200907 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100908 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100909 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +0200910 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100911
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200912 if (buf[0] == '\0') {
913 *trigger = NULL;
914 return 0;
915 }
916
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100917 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +0200918 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100919 const struct iio_device *cur = dev->ctx->devices[i];
920 if (cur->name && !strcmp(cur->name, buf)) {
921 *trigger = cur;
922 return 0;
923 }
924 }
925 return -ENXIO;
926}
927
928static int local_set_trigger(const struct iio_device *dev,
929 const struct iio_device *trigger)
930{
931 ssize_t nb;
932 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +0200933 nb = local_write_dev_attr(dev, "trigger/current_trigger",
934 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100935 if (nb < 0)
936 return (int) nb;
937 else
938 return 0;
939}
940
Lars-Peter Clausend9806c22016-01-26 16:35:42 +0100941static bool is_channel(const char *attr, bool strict)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100942{
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100943 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +0100944 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
945 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100946 if (!strncmp(attr, "in_", 3))
947 ptr = strchr(attr + 3, '_');
948 else if (!strncmp(attr, "out_", 4))
949 ptr = strchr(attr + 4, '_');
950 if (!ptr)
951 return false;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +0100952 if (!strict)
953 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100954 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
955 return true;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100956
957 if (find_modifier(ptr + 1, NULL) != IIO_NO_MOD)
958 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100959 return false;
960}
961
962static char * get_channel_id(const char *attr)
963{
964 char *res, *ptr;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100965 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100966
967 attr = strchr(attr, '_') + 1;
968 ptr = strchr(attr, '_');
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100969 if (find_modifier(ptr + 1, &len) != IIO_NO_MOD)
970 ptr += len + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100971
972 res = malloc(ptr - attr + 1);
973 if (!res)
974 return NULL;
975
976 memcpy(res, attr, ptr - attr);
977 res[ptr - attr] = 0;
978 return res;
979}
980
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200981static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100982{
983 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100984 size_t len;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200985
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100986 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100987 if (find_modifier(ptr, &len) != IIO_NO_MOD)
988 ptr += len + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200989
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200990 if (chn->name) {
991 size_t len = strlen(chn->name);
992 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
993 ptr += len + 1;
994 }
995
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100996 return strdup(ptr);
997}
998
999static int read_device_name(struct iio_device *dev)
1000{
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001001 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +02001002 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +01001003 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001004 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +01001005 else if (ret == 0)
1006 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001007
Paul Cercueil30430c72014-02-17 16:52:37 +01001008 dev->name = strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001009 if (!dev->name)
1010 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +01001011 else
1012 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001013}
1014
1015static int add_attr_to_device(struct iio_device *dev, const char *attr)
1016{
Paul Cercueilbb618272014-02-20 11:35:52 +01001017 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001018 unsigned int i;
1019
1020 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
1021 if (!strcmp(device_attrs_blacklist[i], attr))
1022 return 0;
1023
1024 if (!strcmp(attr, "name"))
1025 return read_device_name(dev);
1026
1027 name = strdup(attr);
1028 if (!name)
1029 return -ENOMEM;
1030
1031 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
1032 if (!attrs) {
1033 free(name);
1034 return -ENOMEM;
1035 }
1036
1037 attrs[dev->nb_attrs++] = name;
1038 dev->attrs = attrs;
1039 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
1040 return 0;
1041}
1042
Paul Cercueile3fbd952014-03-11 16:58:33 +01001043static int add_attr_to_channel(struct iio_channel *chn,
1044 const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001045{
Paul Cercueilb34e0222014-05-05 15:32:38 +02001046 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001047 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001048 if (!name)
1049 return -ENOMEM;
1050
Paul Cercueile3fbd952014-03-11 16:58:33 +01001051 fn = strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +01001052 if (!fn)
1053 goto err_free_name;
1054
Paul Cercueilb34e0222014-05-05 15:32:38 +02001055 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
1056 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +01001057 if (!attrs)
1058 goto err_free_fn;
1059
Paul Cercueil42d12352014-05-05 16:11:58 +02001060 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +02001061 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001062 chn->attrs = attrs;
1063 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
1064 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +01001065
Paul Cercueil167d3112014-02-18 12:23:53 +01001066err_free_fn:
1067 free(fn);
1068err_free_name:
1069 free(name);
1070 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001071}
1072
1073static int add_channel_to_device(struct iio_device *dev,
1074 struct iio_channel *chn)
1075{
1076 struct iio_channel **channels = realloc(dev->channels,
1077 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
1078 if (!channels)
1079 return -ENOMEM;
1080
1081 channels[dev->nb_channels++] = chn;
1082 dev->channels = channels;
1083 DEBUG("Added channel \'%s\' to device \'%s\'\n", chn->id, dev->id);
1084 return 0;
1085}
1086
1087static int add_device_to_context(struct iio_context *ctx,
1088 struct iio_device *dev)
1089{
1090 struct iio_device **devices = realloc(ctx->devices,
1091 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
1092 if (!devices)
1093 return -ENOMEM;
1094
1095 devices[ctx->nb_devices++] = dev;
1096 ctx->devices = devices;
1097 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
1098 return 0;
1099}
1100
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001101static struct iio_channel *create_channel(struct iio_device *dev,
1102 char *id, const char *attr, const char *path)
1103{
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001104 struct iio_channel *chn = zalloc(sizeof(*chn));
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001105 if (!chn)
1106 return NULL;
1107
1108 if (!strncmp(attr, "out_", 4))
1109 chn->is_output = true;
1110 else if (strncmp(attr, "in_", 3))
1111 goto err_free_chn;
1112
1113 chn->dev = dev;
1114 chn->id = id;
1115
1116 if (!add_attr_to_channel(chn, attr, path))
1117 return chn;
1118
1119err_free_chn:
1120 free(chn);
1121 return NULL;
1122}
1123
1124static int add_channel(struct iio_device *dev, const char *name,
1125 const char *path, bool dir_is_scan_elements)
1126{
1127 struct iio_channel *chn;
1128 char *channel_id;
1129 unsigned int i;
1130 int ret;
1131
1132 channel_id = get_channel_id(name);
1133 if (!channel_id)
1134 return -ENOMEM;
1135
1136 for (i = 0; i < dev->nb_channels; i++) {
1137 chn = dev->channels[i];
1138 if (!strcmp(chn->id, channel_id)
1139 && chn->is_output == (name[0] == 'o')) {
1140 free(channel_id);
1141 ret = add_attr_to_channel(chn, name, path);
1142 chn->is_scan_element = dir_is_scan_elements && !ret;
1143 return ret;
1144 }
1145 }
1146
1147 chn = create_channel(dev, channel_id, name, path);
1148 if (!chn) {
1149 free(channel_id);
1150 return -ENXIO;
1151 }
1152 ret = add_channel_to_device(dev, chn);
1153 if (ret)
1154 free_channel(chn);
1155 else
1156 chn->is_scan_element = dir_is_scan_elements;
1157 return ret;
1158}
1159
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001160/*
1161 * Possible return values:
1162 * 0 = Attribute should not be moved to the channel
1163 * 1 = Attribute should be moved to the channel and it is a shared attribute
1164 * 2 = Attribute should be moved to the channel and it is a private attribute
1165 */
1166static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001167{
Lars-Peter Clausen8ba0d5b2016-02-17 11:30:23 +01001168 unsigned int len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001169 char *ptr;
1170
Paul Cercueil35a01312014-02-20 10:56:57 +01001171 if (!chn->is_output && !strncmp(attr, "in_", 3))
1172 attr += 3;
1173 else if (chn->is_output && !strncmp(attr, "out_", 4))
1174 attr += 4;
1175 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001176 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001177
1178 ptr = strchr(attr, '_');
1179 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001180 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001181
1182 len = ptr - attr;
1183
1184 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001185 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001186
1187 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001188 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1189 if (chn->name) {
1190 size_t name_len = strlen(chn->name);
1191 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1192 attr[len + 1 + name_len] == '_')
1193 return 2;
1194 }
1195 return 1;
1196 } else if (chn->id[len] != '_') {
1197 return 0;
1198 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001199
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001200 if (find_modifier(chn->id + len + 1, NULL) != IIO_NO_MOD)
1201 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001202
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001203 return 0;
1204}
1205
1206static int detect_global_attr(struct iio_device *dev, const char *attr,
1207 unsigned int level, bool *match)
1208{
1209 unsigned int i;
1210
1211 *match = false;
1212 for (i = 0; i < dev->nb_channels; i++) {
1213 struct iio_channel *chn = dev->channels[i];
1214 if (is_global_attr(chn, attr) == level) {
1215 int ret;
1216 *match = true;
1217 ret = add_attr_to_channel(chn, attr, attr);
1218 if (ret)
1219 return ret;
1220 }
1221 }
1222
1223 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001224}
1225
1226static int detect_and_move_global_attrs(struct iio_device *dev)
1227{
1228 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001229 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001230
1231 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001232 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001233 bool match;
1234 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001235
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001236 ret = detect_global_attr(dev, attr, 2, &match);
1237 if (ret)
1238 return ret;
1239
1240 if (!match) {
1241 ret = detect_global_attr(dev, attr, 1, &match);
1242 if (ret)
1243 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001244 }
1245
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001246 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001247 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001248 dev->attrs[i] = NULL;
1249 }
1250 }
1251
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001252 /* Find channels without an index */
1253 for (i = 0; i < dev->nb_attrs; i++) {
1254 const char *attr = dev->attrs[i];
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001255 int ret;
1256
1257 if (!dev->attrs[i])
1258 continue;
1259
1260 if (is_channel(attr, false)) {
1261 ret = add_channel(dev, attr, attr, false);
1262 if (ret)
1263 return ret;
1264
1265 free(dev->attrs[i]);
1266 dev->attrs[i] = NULL;
1267 }
1268 }
1269
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001270 for (i = 0; i < dev->nb_attrs; i++) {
1271 if (dev->attrs[i])
1272 *ptr++ = dev->attrs[i];
1273 }
1274
1275 dev->nb_attrs = ptr - dev->attrs;
Lars-Peter Clausene8a2bb32016-04-12 18:43:31 +02001276 if (!dev->nb_attrs) {
1277 free(dev->attrs);
1278 dev->attrs = NULL;
1279 }
1280
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001281 return 0;
1282}
1283
Paul Cercueile3fbd952014-03-11 16:58:33 +01001284static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001285 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001286{
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001287 char buf[1024];
Paul Cercueil1be57832014-03-11 16:27:16 +01001288 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001289
1290 if (dir_is_scan_elements) {
1291 snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001292 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001293 } else {
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001294 if (!is_channel(name, true))
1295 return add_attr_to_device(dev, name);
Paul Cercueila91358e2014-04-24 16:40:19 +02001296 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001297 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001298
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001299 return add_channel(dev, name, path, dir_is_scan_elements);
Paul Cercueil1be57832014-03-11 16:27:16 +01001300}
1301
Paul Cercueile3fbd952014-03-11 16:58:33 +01001302static int add_attr_or_channel(void *d, const char *path)
1303{
Paul Cercueila91358e2014-04-24 16:40:19 +02001304 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001305}
1306
1307static int add_scan_element(void *d, const char *path)
1308{
Paul Cercueila91358e2014-04-24 16:40:19 +02001309 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001310}
1311
Paul Cercueil1be57832014-03-11 16:27:16 +01001312static int foreach_in_dir(void *d, const char *path, bool is_dir,
1313 int (*callback)(void *, const char *))
1314{
1315 long name_max;
1316 struct dirent *entry, *result;
1317 DIR *dir = opendir(path);
1318 if (!dir)
1319 return -errno;
1320
1321 name_max = pathconf(path, _PC_NAME_MAX);
1322 if (name_max == -1)
1323 name_max = 255;
1324 entry = malloc(offsetof(struct dirent, d_name) + name_max + 1);
1325 if (!entry) {
1326 closedir(dir);
1327 return -ENOMEM;
1328 }
1329
1330 while (true) {
1331 struct stat st;
1332 char buf[1024];
1333 int ret = readdir_r(dir, entry, &result);
1334 if (ret) {
Paul Cercueil87b988f2015-05-22 10:57:32 +02001335 iio_strerror(ret, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001336 ERROR("Unable to open directory %s: %s\n", path, buf);
1337 free(entry);
1338 closedir(dir);
Paul Cercueilc57da332015-03-16 17:09:48 +01001339 return -ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001340 }
1341 if (!result)
1342 break;
1343
1344 snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
1345 if (stat(buf, &st) < 0) {
1346 ret = -errno;
Paul Cercueil87b988f2015-05-22 10:57:32 +02001347 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001348 ERROR("Unable to stat file: %s\n", buf);
1349 free(entry);
1350 closedir(dir);
1351 return ret;
1352 }
1353
1354 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1355 ret = callback(d, buf);
1356 else if (!is_dir && S_ISREG(st.st_mode))
1357 ret = callback(d, buf);
1358 else
1359 continue;
1360
1361 if (ret < 0) {
1362 free(entry);
1363 closedir(dir);
1364 return ret;
1365 }
1366 }
1367
1368 free(entry);
1369 closedir(dir);
1370 return 0;
1371}
1372
Paul Cercueile3fbd952014-03-11 16:58:33 +01001373static int add_scan_elements(struct iio_device *dev, const char *devpath)
1374{
1375 struct stat st;
1376 char buf[1024];
1377 snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
1378
1379 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1380 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1381 if (ret < 0)
1382 return ret;
1383 }
1384
1385 return 0;
1386}
1387
Paul Cercueil1be57832014-03-11 16:27:16 +01001388static int create_device(void *d, const char *path)
1389{
Paul Cercueilff778232014-03-24 14:23:08 +01001390 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001391 unsigned int i;
1392 int ret;
1393 struct iio_context *ctx = d;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001394 struct iio_device *dev = zalloc(sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001395 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001396 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001397
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001398 dev->pdata = zalloc(sizeof(*dev->pdata));
Paul Cercueileaab6582014-02-21 09:35:59 +01001399 if (!dev->pdata) {
1400 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001401 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001402 }
1403
Romain Roffé6ce74a22015-06-30 11:45:11 +02001404 dev->pdata->fd = -1;
Romain Roffécead1da2015-06-30 13:35:51 +02001405 dev->pdata->blocking = true;
Romain Roffé0f737472015-06-30 16:45:54 +02001406 dev->pdata->nb_blocks = NB_BLOCKS;
Romain Roffé6ce74a22015-06-30 11:45:11 +02001407
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001408 dev->ctx = ctx;
Paul Cercueil1be57832014-03-11 16:27:16 +01001409 dev->id = strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001410 if (!dev->id) {
Romain Roffé0f737472015-06-30 16:45:54 +02001411 local_free_pdata(dev);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001412 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001413 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001414 }
1415
Paul Cercueil1be57832014-03-11 16:27:16 +01001416 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
1417 if (ret < 0) {
1418 free_device(dev);
1419 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001420 }
1421
Michael Hennerichebe49662014-11-07 10:32:44 +01001422 ret = add_scan_elements(dev, path);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001423 if (ret < 0) {
1424 free_device(dev);
1425 return ret;
1426 }
1427
Paul Cercueilbab69a92015-07-03 11:24:17 +02001428 for (i = 0; i < dev->nb_channels; i++)
1429 set_channel_name(dev->channels[i]);
1430
Michael Hennerichebe49662014-11-07 10:32:44 +01001431 ret = detect_and_move_global_attrs(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001432 if (ret < 0) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001433 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001434 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001435 }
1436
Paul Cercueilff778232014-03-24 14:23:08 +01001437 dev->words = (dev->nb_channels + 31) / 32;
1438 if (dev->words) {
1439 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001440 if (!mask) {
1441 free_device(dev);
1442 return ret;
1443 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001444 }
1445
Paul Cercueilff778232014-03-24 14:23:08 +01001446 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001447
Paul Cercueil1be57832014-03-11 16:27:16 +01001448 ret = add_device_to_context(ctx, dev);
1449 if (ret < 0)
1450 free_device(dev);
1451 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001452}
1453
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001454static int add_debug_attr(void *d, const char *path)
1455{
1456 struct iio_device *dev = d;
1457 const char *attr = strrchr(path, '/') + 1;
1458 char **attrs, *name = strdup(attr);
1459 if (!name)
1460 return -ENOMEM;
1461
1462 attrs = realloc(dev->debug_attrs,
1463 (1 + dev->nb_debug_attrs) * sizeof(char *));
1464 if (!attrs) {
1465 free(name);
1466 return -ENOMEM;
1467 }
1468
1469 attrs[dev->nb_debug_attrs++] = name;
1470 dev->debug_attrs = attrs;
1471 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1472 return 0;
1473}
1474
1475static int add_debug(void *d, const char *path)
1476{
1477 struct iio_context *ctx = d;
1478 const char *name = strrchr(path, '/') + 1;
1479 struct iio_device *dev = iio_context_find_device(ctx, name);
1480 if (!dev)
1481 return -ENODEV;
1482 else
1483 return foreach_in_dir(dev, path, false, add_debug_attr);
1484}
1485
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001486static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1487{
Paul Cercueil00558f12016-04-12 14:40:40 +02001488 ctx->pdata->rw_timeout_ms = timeout;
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001489 return 0;
1490}
1491
Paul Cercueil0865e802014-10-28 14:35:19 +01001492static struct iio_context * local_clone(
1493 const struct iio_context *ctx __attribute__((unused)))
1494{
Paul Cercueil63e52182014-12-11 12:52:48 +01001495 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001496}
1497
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001498static const struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001499 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001500 .open = local_open,
1501 .close = local_close,
Romain Roffé87897862015-06-30 13:34:08 +02001502 .get_fd = local_get_fd,
Romain Roffécead1da2015-06-30 13:35:51 +02001503 .set_blocking_mode = local_set_blocking_mode,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001504 .read = local_read,
1505 .write = local_write,
Romain Roffé0f737472015-06-30 16:45:54 +02001506 .set_kernel_buffers_count = local_set_kernel_buffers_count,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001507 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001508 .read_device_attr = local_read_dev_attr,
1509 .write_device_attr = local_write_dev_attr,
1510 .read_channel_attr = local_read_chn_attr,
1511 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001512 .get_trigger = local_get_trigger,
1513 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001514 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001515 .set_timeout = local_set_timeout,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001516};
1517
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001518static void init_index(struct iio_channel *chn)
1519{
1520 char buf[1024];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001521 long id = -ENOENT;
1522
1523 if (chn->is_scan_element) {
1524 id = (long) local_read_chn_attr(chn, "index", buf, sizeof(buf));
1525 if (id > 0)
1526 id = atol(buf);
1527 }
1528 chn->index = id;
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001529}
1530
1531static void init_data_format(struct iio_channel *chn)
1532{
1533 char buf[1024];
1534 ssize_t ret;
1535
1536 if (chn->is_scan_element) {
1537 ret = local_read_chn_attr(chn, "type", buf, sizeof(buf));
1538 if (ret < 0) {
1539 chn->format.length = 0;
1540 } else {
1541 char endian, sign;
1542
1543 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
1544 &chn->format.bits, &chn->format.length,
1545 &chn->format.shift);
Michael Hennerichfa3c6f62014-08-13 11:21:23 +02001546 chn->format.is_signed = (sign == 's' || sign == 'S');
1547 chn->format.is_fully_defined =
1548 (sign == 'S' || sign == 'U'||
1549 chn->format.bits == chn->format.length);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001550 chn->format.is_be = endian == 'b';
1551 }
1552 }
1553
1554 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1555 if (ret < 0) {
1556 chn->format.with_scale = false;
1557 } else {
1558 chn->format.with_scale = true;
1559 chn->format.scale = atof(buf);
1560 }
1561}
1562
1563static void init_scan_elements(struct iio_context *ctx)
1564{
1565 unsigned int i, j;
1566
1567 for (i = 0; i < ctx->nb_devices; i++) {
1568 struct iio_device *dev = ctx->devices[i];
1569
1570 for (j = 0; j < dev->nb_channels; j++) {
1571 struct iio_channel *chn = dev->channels[j];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001572 init_index(chn);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001573 init_data_format(chn);
1574 }
1575 }
1576}
1577
Paul Cercueil63e52182014-12-11 12:52:48 +01001578struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001579{
Paul Cercueilfd387472015-08-05 10:34:19 +02001580 int ret = -ENOMEM;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001581 unsigned int len;
1582 struct utsname uts;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001583 struct iio_context *ctx = zalloc(sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001584 if (!ctx)
Paul Cercueilfd387472015-08-05 10:34:19 +02001585 goto err_set_errno;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001586
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001587 ctx->ops = &local_ops;
1588 ctx->name = "local";
Paul Cercueil00558f12016-04-12 14:40:40 +02001589
1590 ctx->pdata = zalloc(sizeof(*ctx->pdata));
1591 if (!ctx->pdata) {
1592 free(ctx);
1593 goto err_set_errno;
1594 }
1595
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001596 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001597
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001598 uname(&uts);
1599 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
1600 + strlen(uts.version) + strlen(uts.machine);
1601 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
1602 if (!ctx->description) {
Paul Cercueil00558f12016-04-12 14:40:40 +02001603 free(ctx->pdata);
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001604 free(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001605 goto err_set_errno;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001606 }
1607
1608 snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
1609 uts.nodename, uts.release, uts.version, uts.machine);
1610
Paul Cercueil1be57832014-03-11 16:27:16 +01001611 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
Paul Cercueilfd387472015-08-05 10:34:19 +02001612 if (ret < 0)
1613 goto err_context_destroy;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001614
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001615 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001616
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001617 init_scan_elements(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001618 ret = iio_context_init(ctx);
1619 if (ret < 0)
1620 goto err_context_destroy;
Paul Cercueilae88fde2014-03-12 11:47:10 +01001621
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001622 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001623
Paul Cercueilfd387472015-08-05 10:34:19 +02001624err_context_destroy:
1625 iio_context_destroy(ctx);
1626err_set_errno:
1627 errno = -ret;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001628 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001629}