blob: debc7f7c430e08ffdc255984a340c9f8760463b9 [file] [log] [blame]
Paul Cercueilbb4401d2014-02-28 16:10:49 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * */
18
Paul Cercueil0b2ce712014-02-17 15:04:18 +010019#include "debug.h"
20#include "iio-private.h"
21
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020022#include <arpa/inet.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010023#include <dirent.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010024#include <errno.h>
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020025#include <poll.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010026#include <stdbool.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010027#include <stddef.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010028#include <stdio.h>
29#include <string.h>
Paul Cercueil92f46df2014-04-28 13:17:53 +020030#include <sys/ioctl.h>
31#include <sys/mman.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010032#include <sys/types.h>
33#include <sys/stat.h>
34#include <unistd.h>
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +020035#include <string.h>
Lars-Peter Clausen00f80092014-07-01 17:52:05 +020036#include <sys/utsname.h>
Romain Roffécead1da2015-06-30 13:35:51 +020037#include <unistd.h>
Romain Roffé6ce74a22015-06-30 11:45:11 +020038#include <fcntl.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010039
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020040#define DEFAULT_TIMEOUT_MS 1000
41
Paul Cercueil92f46df2014-04-28 13:17:53 +020042#define NB_BLOCKS 4
43
44#define BLOCK_ALLOC_IOCTL _IOWR('i', 0xa0, struct block_alloc_req)
45#define BLOCK_FREE_IOCTL _IO('i', 0xa1)
46#define BLOCK_QUERY_IOCTL _IOWR('i', 0xa2, struct block)
47#define BLOCK_ENQUEUE_IOCTL _IOWR('i', 0xa3, struct block)
48#define BLOCK_DEQUEUE_IOCTL _IOWR('i', 0xa4, struct block)
49
Paul Cercueil71694c72014-05-22 14:02:13 +020050#define BLOCK_FLAG_CYCLIC BIT(1)
51
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020052/* Forward declarations */
53static ssize_t local_read_dev_attr(const struct iio_device *dev,
54 const char *attr, char *dst, size_t len, bool is_debug);
55static ssize_t local_read_chn_attr(const struct iio_channel *chn,
56 const char *attr, char *dst, size_t len);
Paul Cercueil1da28122014-05-22 10:59:49 +020057static ssize_t local_write_dev_attr(const struct iio_device *dev,
58 const char *attr, const char *src, size_t len, bool is_debug);
59static ssize_t local_write_chn_attr(const struct iio_channel *chn,
60 const char *attr, const char *src, size_t len);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020061
Paul Cercueil92f46df2014-04-28 13:17:53 +020062struct block_alloc_req {
63 uint32_t type,
64 size,
65 count,
66 id;
67};
68
69struct block {
70 uint32_t id,
71 size,
72 bytes_used,
73 type,
74 flags,
75 offset;
76 uint64_t timestamp;
77};
78
Paul Cercueileaab6582014-02-21 09:35:59 +010079struct iio_device_pdata {
Romain Roffé6ce74a22015-06-30 11:45:11 +020080 int fd;
Romain Roffécead1da2015-06-30 13:35:51 +020081 bool blocking;
Paul Cercueil71694c72014-05-22 14:02:13 +020082 unsigned int samples_count, nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +020083
Romain Roffé0f737472015-06-30 16:45:54 +020084 struct block *blocks;
85 void **addrs;
Paul Cercueil92f46df2014-04-28 13:17:53 +020086 int last_dequeued;
Paul Cercueil6ea8a752014-06-03 11:35:35 +020087 bool is_high_speed, cyclic, cyclic_buffer_enqueued, buffer_enabled;
Paul Cercueileaab6582014-02-21 09:35:59 +010088};
89
Paul Cercueil0b2ce712014-02-17 15:04:18 +010090static const char * const device_attrs_blacklist[] = {
91 "dev",
92 "uevent",
93};
94
95static const char * const modifier_names[] = {
96 [IIO_MOD_X] = "x",
97 [IIO_MOD_Y] = "y",
98 [IIO_MOD_Z] = "z",
99 [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)",
100 [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
101 [IIO_MOD_LIGHT_BOTH] = "both",
102 [IIO_MOD_LIGHT_IR] = "ir",
103 [IIO_MOD_LIGHT_CLEAR] = "clear",
104 [IIO_MOD_LIGHT_RED] = "red",
105 [IIO_MOD_LIGHT_GREEN] = "green",
106 [IIO_MOD_LIGHT_BLUE] = "blue",
Lars-Peter Clausen60aa4042015-03-27 13:34:55 +0100107 [IIO_MOD_I] = "i",
108 [IIO_MOD_Q] = "q",
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100109};
110
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100111/*
112 * Looks for a IIO channel modifier at the beginning of the string s. If a
113 * modifier was found the symbolic constant (IIO_MOD_*) is returned, otherwise
114 * IIO_NO_MOD is returned. If a modifier was found len_p will be update with the
115 * length of the modifier.
116 */
117static unsigned int find_modifier(const char *s, size_t *len_p)
118{
119 unsigned int i;
120 size_t len;
121
122 for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
123 if (!modifier_names[i])
124 continue;
125 len = strlen(modifier_names[i]);
Paul Cercueil23efdd82015-08-05 11:02:28 +0200126 if (strncmp(s, modifier_names[i], len) == 0 &&
127 (s[len] == '\0' || s[len] == '_')) {
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100128 if (len_p)
129 *len_p = len;
130 return i;
131 }
132 }
133
134 return IIO_NO_MOD;
135}
136
Romain Roffé0f737472015-06-30 16:45:54 +0200137static void local_free_pdata(struct iio_device *device)
138{
139 if (device && device->pdata) {
140 free(device->pdata->blocks);
141 free(device->pdata->addrs);
142 free(device->pdata);
143 }
144}
145
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100146static void local_shutdown(struct iio_context *ctx)
147{
Paul Cercueil42d12352014-05-05 16:11:58 +0200148 /* Free the backend data stored in every device structure */
Paul Cercueil167d3112014-02-18 12:23:53 +0100149 unsigned int i;
Romain Roffé0f737472015-06-30 16:45:54 +0200150 for (i = 0; i < ctx->nb_devices; i++) {
151 local_free_pdata(ctx->devices[i]);
152 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100153}
154
Michael Hennerich1c8aa572014-11-06 17:42:30 +0100155/** Shrinks the first nb characters of a string
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100156 * e.g. strcut("foobar", 4) replaces the content with "ar". */
157static void strcut(char *str, int nb)
158{
159 char *ptr = str + nb;
160 while (*ptr)
161 *str++ = *ptr++;
162 *str = 0;
163}
164
165static int set_channel_name(struct iio_channel *chn)
166{
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100167 size_t prefix_len = 0;
168 const char *attr0;
169 const char *ptr;
170 unsigned int i;
171
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100172 if (chn->nb_attrs < 2)
173 return 0;
174
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100175 attr0 = ptr = chn->attrs[0].name;
176
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100177 while (true) {
178 bool can_fix = true;
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100179 size_t len;
180
181 ptr = strchr(ptr, '_');
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100182 if (!ptr)
183 break;
184
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100185 len = ptr - attr0 + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100186 for (i = 1; can_fix && i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200187 can_fix = !strncmp(attr0, chn->attrs[i].name, len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100188
189 if (!can_fix)
190 break;
191
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100192 prefix_len = len;
193 ptr = ptr + 1;
194 }
195
196 if (prefix_len) {
197 char *name;
198
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100199 name = malloc(prefix_len);
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100200 if (!name)
201 return -ENOMEM;
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100202 strncpy(name, attr0, prefix_len - 1);
203 name[prefix_len - 1] = '\0';
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100204 DEBUG("Setting name of channel %s to %s\n", chn->id, name);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100205 chn->name = name;
206
207 /* Shrink the attribute name */
208 for (i = 0; i < chn->nb_attrs; i++)
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100209 strcut(chn->attrs[i].name, prefix_len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100210 }
211
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100212 return 0;
213}
214
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200215static int device_check_ready(const struct iio_device *dev, bool do_write)
216{
217 struct pollfd pollfd = {
Romain Roffé6ce74a22015-06-30 11:45:11 +0200218 .fd = dev->pdata->fd,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200219 .events = do_write ? POLLOUT : POLLIN,
220 };
Romain Roffé6ce74a22015-06-30 11:45:11 +0200221 int ret;
222
Romain Roffécead1da2015-06-30 13:35:51 +0200223 if (!dev->pdata->blocking)
224 return 0;
225
Romain Roffé6ce74a22015-06-30 11:45:11 +0200226 ret = poll(&pollfd, 1, dev->ctx->rw_timeout_ms);
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200227 if (ret < 0)
228 return -errno;
229 if (!ret)
230 return -ETIMEDOUT;
231 if (pollfd.revents & POLLNVAL)
232 return -EBADF;
233 if (!(pollfd.revents & (do_write ? POLLOUT : POLLIN)))
234 return -EIO;
235 return 0;
236}
237
Romain Roffé6ce74a22015-06-30 11:45:11 +0200238static ssize_t read_all(void *dst, size_t len, int fd)
239{
240 uintptr_t ptr = (uintptr_t) dst;
241 ssize_t readsize;
242 int ret;
243
244 while (len > 0) {
245 do {
246 ret = read(fd, (void *) ptr, len);
247 } while (ret == -1 && errno == EINTR);
248
249 if (ret == -1) {
250 ret = -errno;
251 break;
252 } else if (ret == 0) {
253 ret = -EIO;
254 break;
255 }
256
257 ptr += ret;
258 len -= ret;
259 }
260
261 readsize = (ssize_t)(ptr - (uintptr_t) dst);
Romain Roffécead1da2015-06-30 13:35:51 +0200262 if ((ret > 0 || ret == -EAGAIN) && (readsize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200263 return readsize;
264 else
265 return ret;
266}
267
268static ssize_t write_all(const void *src, size_t len, int fd)
269{
270 uintptr_t ptr = (uintptr_t) src;
271 ssize_t writtensize;
272 int ret;
273
274 while (len > 0) {
275 do {
276 ret = write(fd, (void *) ptr, len);
277 } while (ret == -1 && errno == EINTR);
278
279 if (ret == -1) {
280 ret = -errno;
281 break;
282 } else if (ret == 0) {
283 ret = -EIO;
284 break;
285 }
286
287 ptr += ret;
288 len -= ret;
289 }
290
291 writtensize = (ssize_t)(ptr - (uintptr_t) src);
Romain Roffécead1da2015-06-30 13:35:51 +0200292 if ((ret > 0 || ret == -EAGAIN) && (writtensize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200293 return writtensize;
294 else
295 return ret;
296}
297
Romain Roffécead1da2015-06-30 13:35:51 +0200298static ssize_t local_enable_buffer(const struct iio_device *dev)
299{
300 struct iio_device_pdata *pdata = dev->pdata;
301 ssize_t ret = 0;
302
303 if (!pdata->buffer_enabled) {
304 ret = local_write_dev_attr(dev,
305 "buffer/enable", "1", 2, false);
306 if (ret >= 0)
307 pdata->buffer_enabled = true;
308 }
309
310 return 0;
311}
Romain Roffé6ce74a22015-06-30 11:45:11 +0200312
Paul Cercueil45c575d2014-03-20 15:14:01 +0100313static ssize_t local_read(const struct iio_device *dev,
314 void *dst, size_t len, uint32_t *mask, size_t words)
Paul Cercueil44010ea2014-02-21 11:47:04 +0100315{
316 ssize_t ret;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200317 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200318 if (pdata->fd == -1)
Paul Cercueil44010ea2014-02-21 11:47:04 +0100319 return -EBADF;
Paul Cercueilff778232014-03-24 14:23:08 +0100320 if (words != dev->words)
Paul Cercueil45c575d2014-03-20 15:14:01 +0100321 return -EINVAL;
322
Romain Roffécead1da2015-06-30 13:35:51 +0200323 ret = local_enable_buffer(dev);
324 if (ret < 0)
325 return ret;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200326
Lars-Peter Clausen666cfe52014-07-14 11:43:15 +0200327 ret = device_check_ready(dev, false);
328 if (ret < 0)
329 return ret;
330
Paul Cercueilff778232014-03-24 14:23:08 +0100331 memcpy(mask, dev->mask, words);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200332 ret = read_all(dst, len, pdata->fd);
333
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200334 return ret ? ret : -EIO;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100335}
336
337static ssize_t local_write(const struct iio_device *dev,
338 const void *src, size_t len)
339{
340 ssize_t ret;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200341 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200342 if (pdata->fd == -1)
Paul Cercueil44010ea2014-02-21 11:47:04 +0100343 return -EBADF;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200344
Paul Cercueil91d25ac2014-05-27 10:52:42 +0200345 /* Writing is forbidden in cyclic mode with devices without the
346 * high-speed mmap interface, except for the devices starting with
347 * "cf-": in this case only cyclic mode is allowed. */
Paul Cercueild9d9e4d2014-05-27 11:49:35 +0200348 if (!pdata->is_high_speed && pdata->cyclic !=
349 (dev->name && !strncmp(dev->name, "cf-", 3)))
Paul Cercueild55a7482015-11-27 13:39:57 +0100350 return -EPERM;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200351
Paul Cercueil82139cc2014-09-02 15:51:00 +0200352 if (pdata->cyclic) {
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200353 ret = device_check_ready(dev, true);
354 if (ret < 0)
355 return ret;
356
Romain Roffé6ce74a22015-06-30 11:45:11 +0200357 ret = write(pdata->fd, src, len);
Paul Cercueil82139cc2014-09-02 15:51:00 +0200358 if (ret < 0)
359 return -errno;
360 }
361
Romain Roffécead1da2015-06-30 13:35:51 +0200362 ret = local_enable_buffer(dev);
363 if (ret < 0)
364 return ret;
Paul Cercueil82139cc2014-09-02 15:51:00 +0200365
366 /* In cyclic mode, the buffer must be enabled after writing the samples.
367 * In non-cyclic mode, it must be enabled before writing the samples. */
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200368 if (!pdata->cyclic) {
369 ret = device_check_ready(dev, true);
370 if (ret < 0)
371 return ret;
372
Romain Roffé6ce74a22015-06-30 11:45:11 +0200373 ret = write_all(src, len, pdata->fd);
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200374 }
Paul Cercueil82139cc2014-09-02 15:51:00 +0200375
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200376 return ret ? ret : -EIO;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100377}
378
Romain Roffé0f737472015-06-30 16:45:54 +0200379static int local_set_kernel_buffers_count(const struct iio_device *dev,
380 unsigned int nb_blocks)
381{
382 struct iio_device_pdata *pdata = dev->pdata;
383
384 if (pdata->fd != -1)
385 return -EBUSY;
386
387 pdata->nb_blocks = nb_blocks;
388
389 return 0;
390}
391
Paul Cercueil92f46df2014-04-28 13:17:53 +0200392static ssize_t local_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100393 void **addr_ptr, size_t bytes_used,
394 uint32_t *mask, size_t words)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200395{
396 struct block block;
397 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200398 int f = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200399 ssize_t ret;
400
401 if (!pdata->is_high_speed)
402 return -ENOSYS;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200403 if (f == -1)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200404 return -EBADF;
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200405 if (!addr_ptr)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200406 return -EINVAL;
407
Paul Cercueil92f46df2014-04-28 13:17:53 +0200408 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200409 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200410
411 if (pdata->cyclic) {
412 if (pdata->cyclic_buffer_enqueued)
413 return -EBUSY;
414 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
415 pdata->cyclic_buffer_enqueued = true;
416 }
417
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200418 last_block->bytes_used = bytes_used;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200419 ret = (ssize_t) ioctl(f,
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200420 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200421 if (ret) {
422 ret = (ssize_t) -errno;
423 ERROR("Unable to enqueue block: %s\n", strerror(errno));
424 return ret;
425 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200426
427 if (pdata->cyclic) {
428 *addr_ptr = pdata->addrs[pdata->last_dequeued];
429 return (ssize_t) last_block->bytes_used;
430 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200431 }
432
Nicholas Pillitteric65095d2015-05-18 20:11:47 -0400433 memset(&block, 0, sizeof(block));
Romain Roffé6ce74a22015-06-30 11:45:11 +0200434 ret = (ssize_t) ioctl(f, BLOCK_DEQUEUE_IOCTL, &block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200435 if (ret) {
436 ret = (ssize_t) -errno;
437 ERROR("Unable to dequeue block: %s\n", strerror(errno));
438 return ret;
439 }
440
Paul Cercueil558ade42014-11-27 10:59:48 +0100441 /* Requested buffer size is too big! */
442 if (pdata->last_dequeued < 0 && bytes_used != block.size)
443 return -EFBIG;
444
Paul Cercueil92f46df2014-04-28 13:17:53 +0200445 pdata->last_dequeued = block.id;
446 *addr_ptr = pdata->addrs[block.id];
447 return (ssize_t) block.bytes_used;
448}
449
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200450static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
451 char *dst, size_t len, bool is_debug)
452{
453 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
454 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
455 char *ptr = dst;
456
457 for (i = 0; len >= 4 && i < nb; i++) {
458 /* Recursive! */
459 ssize_t ret = local_read_dev_attr(dev, attrs[i],
460 ptr + 4, len - 4, is_debug);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200461 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200462
463 /* Align the length to 4 bytes */
464 if (ret > 0 && ret & 3)
465 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200466 ptr += 4 + (ret < 0 ? 0 : ret);
467 len -= 4 + (ret < 0 ? 0 : ret);
468 }
469
470 return ptr - dst;
471}
472
473static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
474 char *dst, size_t len)
475{
476 unsigned int i;
477 char *ptr = dst;
478
479 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
480 /* Recursive! */
481 ssize_t ret = local_read_chn_attr(chn,
482 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200483 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200484
485 /* Align the length to 4 bytes */
486 if (ret > 0 && ret & 3)
487 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200488 ptr += 4 + (ret < 0 ? 0 : ret);
489 len -= 4 + (ret < 0 ? 0 : ret);
490 }
491
492 return ptr - dst;
493}
494
Paul Cercueil1da28122014-05-22 10:59:49 +0200495static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
496{
497 while (nb--) {
498 int32_t val;
499
500 if (len < 4)
501 return -EINVAL;
502
503 val = (int32_t) ntohl(*(uint32_t *) src);
504 src += 4;
505 len -= 4;
506
507 if (val > 0) {
508 if ((uint32_t) val > len)
509 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200510
511 /* Align the length to 4 bytes */
512 if (val & 3)
513 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200514 len -= val;
515 src += val;
516 }
517 }
518
519 /* We should have analyzed the whole buffer by now */
520 return !len ? 0 : -EINVAL;
521}
522
523static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
524 const char *src, size_t len, bool is_debug)
525{
526 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
527 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
528 const char *ptr = src;
529
530 /* First step: Verify that the buffer is in the correct format */
531 if (local_buffer_analyze(nb, src, len))
532 return -EINVAL;
533
534 /* Second step: write the attributes */
535 for (i = 0; i < nb; i++) {
536 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
537 ptr += 4;
538
539 if (val > 0) {
540 local_write_dev_attr(dev, attrs[i], ptr, val, is_debug);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200541
542 /* Align the length to 4 bytes */
543 if (val & 3)
544 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200545 ptr += val;
546 }
547 }
548
549 return ptr - src;
550}
551
552static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
553 const char *src, size_t len)
554{
555 unsigned int i, nb = chn->nb_attrs;
556 const char *ptr = src;
557
558 /* First step: Verify that the buffer is in the correct format */
559 if (local_buffer_analyze(nb, src, len))
560 return -EINVAL;
561
562 /* Second step: write the attributes */
563 for (i = 0; i < nb; i++) {
564 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
565 ptr += 4;
566
567 if (val > 0) {
568 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200569
570 /* Align the length to 4 bytes */
571 if (val & 3)
572 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200573 ptr += val;
574 }
575 }
576
577 return ptr - src;
578}
579
Paul Cercueil167d3112014-02-18 12:23:53 +0100580static ssize_t local_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200581 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100582{
Paul Cercueil3e898302014-02-17 16:17:11 +0100583 FILE *f;
584 char buf[1024];
585 ssize_t ret;
586
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200587 if (!attr)
588 return local_read_all_dev_attrs(dev, dst, len, is_debug);
589
Paul Cercueil50c762a2014-04-14 15:55:43 +0200590 if (is_debug)
591 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
592 dev->id, attr);
593 else
594 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
595 dev->id, attr);
Paul Cercueil3e898302014-02-17 16:17:11 +0100596 f = fopen(buf, "r");
597 if (!f)
598 return -errno;
599
600 ret = fread(dst, 1, len, f);
601 if (ret > 0)
602 dst[ret - 1] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100603 fflush(f);
604 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200605 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100606 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200607 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100608}
609
Paul Cercueil167d3112014-02-18 12:23:53 +0100610static ssize_t local_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200611 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100612{
Paul Cercueil3e898302014-02-17 16:17:11 +0100613 FILE *f;
614 char buf[1024];
615 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100616
Paul Cercueil1da28122014-05-22 10:59:49 +0200617 if (!attr)
618 return local_write_all_dev_attrs(dev, src, len, is_debug);
619
Paul Cercueil50c762a2014-04-14 15:55:43 +0200620 if (is_debug)
621 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
622 dev->id, attr);
623 else
624 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
625 dev->id, attr);
Andrea Galbusera7f83b832014-07-25 18:23:36 +0200626 f = fopen(buf, "w");
Paul Cercueil3e898302014-02-17 16:17:11 +0100627 if (!f)
628 return -errno;
629
630 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100631 fflush(f);
632 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200633 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100634 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200635 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100636}
637
Paul Cercueil167d3112014-02-18 12:23:53 +0100638static const char * get_filename(const struct iio_channel *chn,
639 const char *attr)
640{
Paul Cercueil167d3112014-02-18 12:23:53 +0100641 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200642 for (i = 0; i < chn->nb_attrs; i++)
643 if (!strcmp(attr, chn->attrs[i].name))
644 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100645 return attr;
646}
647
648static ssize_t local_read_chn_attr(const struct iio_channel *chn,
649 const char *attr, char *dst, size_t len)
650{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200651 if (!attr)
652 return local_read_all_chn_attrs(chn, dst, len);
653
Paul Cercueil167d3112014-02-18 12:23:53 +0100654 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200655 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100656}
657
658static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200659 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100660{
Paul Cercueil1da28122014-05-22 10:59:49 +0200661 if (!attr)
662 return local_write_all_chn_attrs(chn, src, len);
663
Paul Cercueil167d3112014-02-18 12:23:53 +0100664 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200665 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100666}
667
Paul Cercueilff778232014-03-24 14:23:08 +0100668static int channel_write_state(const struct iio_channel *chn)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100669{
Paul Cercueilff778232014-03-24 14:23:08 +0100670 char *en = iio_channel_is_enabled(chn) ? "1" : "0";
Paul Cercueilcecda352014-05-06 18:14:29 +0200671 ssize_t ret = local_write_chn_attr(chn, "en", en, 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100672 if (ret < 0)
673 return (int) ret;
674 else
675 return 0;
676}
677
Paul Cercueil92f46df2014-04-28 13:17:53 +0200678static int enable_high_speed(const struct iio_device *dev)
679{
680 struct block_alloc_req req;
681 struct iio_device_pdata *pdata = dev->pdata;
682 unsigned int i;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200683 int ret, fd = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200684
Paul Cercueil71694c72014-05-22 14:02:13 +0200685 if (pdata->cyclic) {
686 pdata->nb_blocks = 1;
687 DEBUG("Enabling cyclic mode\n");
688 } else {
Paul Cercueil71694c72014-05-22 14:02:13 +0200689 DEBUG("Cyclic mode not enabled\n");
690 }
691
Romain Roffé0f737472015-06-30 16:45:54 +0200692 pdata->blocks = calloc(pdata->nb_blocks, sizeof(*pdata->blocks));
693 if (!pdata->blocks) {
694 pdata->nb_blocks = 0;
695 return -ENOMEM;
696 }
697
698 pdata->addrs = calloc(pdata->nb_blocks, sizeof(*pdata->addrs));
699 if (!pdata->addrs) {
700 free(pdata->blocks);
701 pdata->blocks = NULL;
702 return -ENOMEM;
703 }
704
Paul Cercueil1fa913d2015-04-28 16:30:53 +0200705 req.id = 0;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200706 req.type = 0;
707 req.size = pdata->samples_count *
708 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Paul Cercueil71694c72014-05-22 14:02:13 +0200709 req.count = pdata->nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200710
711 ret = ioctl(fd, BLOCK_ALLOC_IOCTL, &req);
Romain Roffé0f737472015-06-30 16:45:54 +0200712 if (ret < 0) {
713 ret = -errno;
714 goto err_freemem;
715 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200716
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200717 /* We might get less blocks than what we asked for */
718 pdata->nb_blocks = req.count;
719
Paul Cercueil92f46df2014-04-28 13:17:53 +0200720 /* mmap all the blocks */
Paul Cercueil71694c72014-05-22 14:02:13 +0200721 for (i = 0; i < pdata->nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200722 pdata->blocks[i].id = i;
723 ret = ioctl(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
724 if (ret) {
725 ret = -errno;
726 goto err_munmap;
727 }
728
729 ret = ioctl(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
730 if (ret) {
731 ret = -errno;
732 goto err_munmap;
733 }
734
Paul Cercueil032a5652014-05-12 17:11:19 +0200735 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
736 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200737 MAP_SHARED, fd, pdata->blocks[i].offset);
738 if (pdata->addrs[i] == MAP_FAILED) {
739 ret = -errno;
740 goto err_munmap;
741 }
742 }
743
Paul Cercueil4a702d32014-05-12 17:02:37 +0200744 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200745 return 0;
746
747err_munmap:
748 for (; i > 0; i--)
749 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
750 ioctl(fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200751err_freemem:
752 free(pdata->addrs);
753 pdata->addrs = NULL;
754 free(pdata->blocks);
755 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200756 return ret;
757}
758
Paul Cercueil92f15c22015-04-20 11:36:51 +0200759static int local_open(const struct iio_device *dev,
760 size_t samples_count, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100761{
762 unsigned int i;
763 int ret;
764 char buf[1024];
765 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200766
Romain Roffé6ce74a22015-06-30 11:45:11 +0200767 if (pdata->fd != -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100768 return -EBUSY;
769
Paul Cercueilcecda352014-05-06 18:14:29 +0200770 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200771 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100772 return ret;
773
Paul Cercueil11334342015-06-23 16:55:35 +0200774 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200775 ret = local_write_dev_attr(dev, "buffer/length",
776 buf, strlen(buf) + 1, false);
777 if (ret < 0)
778 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200779
Paul Cercueil8c29e412014-04-07 09:46:45 +0200780 snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200781 pdata->fd = open(buf, O_RDWR);
782 if (pdata->fd == -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100783 return -errno;
784
Paul Cercueil11334342015-06-23 16:55:35 +0200785 /* Disable channels */
786 for (i = 0; i < dev->nb_channels; i++) {
787 struct iio_channel *chn = dev->channels[i];
788 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
789 ret = channel_write_state(chn);
790 if (ret < 0)
791 goto err_close;
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100792 }
Paul Cercueil11334342015-06-23 16:55:35 +0200793 }
794 /* Enable channels */
795 for (i = 0; i < dev->nb_channels; i++) {
796 struct iio_channel *chn = dev->channels[i];
797 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
798 ret = channel_write_state(chn);
799 if (ret < 0)
800 goto err_close;
Paul Cercueile1311222014-03-12 15:46:16 +0100801 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100802 }
803
Paul Cercueil71694c72014-05-22 14:02:13 +0200804 pdata->cyclic = cyclic;
805 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200806 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200807 pdata->samples_count = samples_count;
Paul Cercueil71694c72014-05-22 14:02:13 +0200808 pdata->is_high_speed = !enable_high_speed(dev);
Paul Cercueilb762fc62014-05-12 16:56:09 +0200809
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200810 if (!pdata->is_high_speed) {
Romain Roffé0f737472015-06-30 16:45:54 +0200811 unsigned long size = samples_count * pdata->nb_blocks;
Paul Cercueil032a5652014-05-12 17:11:19 +0200812 WARNING("High-speed mode not enabled\n");
Paul Cercueiled621ee2015-06-24 10:50:21 +0200813
814 /* Increase the size of the kernel buffer, when using the
815 * low-speed interface. This avoids losing samples when
816 * refilling the iio_buffer. */
Romain Roffé0f737472015-06-30 16:45:54 +0200817 snprintf(buf, sizeof(buf), "%lu", size);
Paul Cercueiled621ee2015-06-24 10:50:21 +0200818 ret = local_write_dev_attr(dev, "buffer/length",
819 buf, strlen(buf) + 1, false);
820 if (ret < 0)
821 goto err_close;
822
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200823 /* NOTE: The low-speed interface will enable the buffer after
Romain Roffécead1da2015-06-30 13:35:51 +0200824 * the first samples are written, or if the device is set
825 * to non blocking-mode */
Paul Cercueiled621ee2015-06-24 10:50:21 +0200826 } else {
Romain Roffécead1da2015-06-30 13:35:51 +0200827 ret = local_enable_buffer(dev);
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200828 if (ret < 0)
829 goto err_close;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200830 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100831
Paul Cercueil45c575d2014-03-20 15:14:01 +0100832 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +0100833err_close:
Romain Roffé6ce74a22015-06-30 11:45:11 +0200834 close(pdata->fd);
835 pdata->fd = -1;
Paul Cercueile1311222014-03-12 15:46:16 +0100836 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100837}
838
839static int local_close(const struct iio_device *dev)
840{
841 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100842 int ret;
843
Paul Cercueilb6a40c22015-07-02 11:12:16 +0200844 if (pdata->fd == -1)
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100845 return -EBADF;
846
Paul Cercueil92f46df2014-04-28 13:17:53 +0200847 if (pdata->is_high_speed) {
848 unsigned int i;
Paul Cercueil71694c72014-05-22 14:02:13 +0200849 for (i = 0; i < pdata->nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200850 munmap(pdata->addrs[i], pdata->blocks[i].size);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200851 ioctl(pdata->fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200852 free(pdata->addrs);
853 pdata->addrs = NULL;
854 free(pdata->blocks);
855 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200856 }
857
Romain Roffé6ce74a22015-06-30 11:45:11 +0200858 ret = close(pdata->fd);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100859 if (ret)
860 return ret;
861
Romain Roffé6ce74a22015-06-30 11:45:11 +0200862 pdata->fd = -1;
Paul Cercueil71694c72014-05-22 14:02:13 +0200863 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
864 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100865}
866
Romain Roffé87897862015-06-30 13:34:08 +0200867static int local_get_fd(const struct iio_device *dev)
868{
Paul Cercueil2cdc81b2015-07-02 11:13:23 +0200869 if (dev->pdata->fd == -1)
870 return -EBADF;
871 else
872 return dev->pdata->fd;
Romain Roffé87897862015-06-30 13:34:08 +0200873}
874
Romain Roffécead1da2015-06-30 13:35:51 +0200875static int local_set_blocking_mode(const struct iio_device *dev, bool blocking)
876{
877 int ret;
878
879 if (dev->pdata->fd == -1)
880 return -EBADF;
881
882 if (dev->pdata->cyclic)
883 return -EPERM;
884
885 ret = set_blocking_mode(dev->pdata->fd, blocking);
886 if (ret == 0) {
887 dev->pdata->blocking = blocking;
888
889 /* When a device is opened, it is configured in blocking mode.
890 * If the user wants to use the non blocking API, and poll the
891 * device to know when to make the first read, it is required to
892 * activate to buffer automatically when the device is switched
893 * in non-blocking mode. */
894 if (!blocking)
895 ret = local_enable_buffer(dev);
896 }
897
898 return ret;
899}
900
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100901static int local_get_trigger(const struct iio_device *dev,
902 const struct iio_device **trigger)
903{
904 char buf[1024];
905 unsigned int i;
906 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +0200907 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +0200908 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100909 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100910 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +0200911 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100912
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200913 if (buf[0] == '\0') {
914 *trigger = NULL;
915 return 0;
916 }
917
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100918 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +0200919 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100920 const struct iio_device *cur = dev->ctx->devices[i];
921 if (cur->name && !strcmp(cur->name, buf)) {
922 *trigger = cur;
923 return 0;
924 }
925 }
926 return -ENXIO;
927}
928
929static int local_set_trigger(const struct iio_device *dev,
930 const struct iio_device *trigger)
931{
932 ssize_t nb;
933 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +0200934 nb = local_write_dev_attr(dev, "trigger/current_trigger",
935 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100936 if (nb < 0)
937 return (int) nb;
938 else
939 return 0;
940}
941
Lars-Peter Clausend9806c22016-01-26 16:35:42 +0100942static bool is_channel(const char *attr, bool strict)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100943{
944 unsigned int i;
945 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +0100946 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
947 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100948 if (!strncmp(attr, "in_", 3))
949 ptr = strchr(attr + 3, '_');
950 else if (!strncmp(attr, "out_", 4))
951 ptr = strchr(attr + 4, '_');
952 if (!ptr)
953 return false;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +0100954 if (!strict)
955 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100956 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
957 return true;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100958
959 if (find_modifier(ptr + 1, NULL) != IIO_NO_MOD)
960 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100961 return false;
962}
963
964static char * get_channel_id(const char *attr)
965{
966 char *res, *ptr;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100967 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100968
969 attr = strchr(attr, '_') + 1;
970 ptr = strchr(attr, '_');
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100971 if (find_modifier(ptr + 1, &len) != IIO_NO_MOD)
972 ptr += len + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100973
974 res = malloc(ptr - attr + 1);
975 if (!res)
976 return NULL;
977
978 memcpy(res, attr, ptr - attr);
979 res[ptr - attr] = 0;
980 return res;
981}
982
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200983static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100984{
985 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100986 size_t len;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200987
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100988 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100989 if (find_modifier(ptr, &len) != IIO_NO_MOD)
990 ptr += len + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200991
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200992 if (chn->name) {
993 size_t len = strlen(chn->name);
994 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
995 ptr += len + 1;
996 }
997
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100998 return strdup(ptr);
999}
1000
1001static int read_device_name(struct iio_device *dev)
1002{
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001003 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +02001004 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +01001005 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001006 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +01001007 else if (ret == 0)
1008 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001009
Paul Cercueil30430c72014-02-17 16:52:37 +01001010 dev->name = strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001011 if (!dev->name)
1012 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +01001013 else
1014 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001015}
1016
1017static int add_attr_to_device(struct iio_device *dev, const char *attr)
1018{
Paul Cercueilbb618272014-02-20 11:35:52 +01001019 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001020 unsigned int i;
1021
1022 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
1023 if (!strcmp(device_attrs_blacklist[i], attr))
1024 return 0;
1025
1026 if (!strcmp(attr, "name"))
1027 return read_device_name(dev);
1028
1029 name = strdup(attr);
1030 if (!name)
1031 return -ENOMEM;
1032
1033 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
1034 if (!attrs) {
1035 free(name);
1036 return -ENOMEM;
1037 }
1038
1039 attrs[dev->nb_attrs++] = name;
1040 dev->attrs = attrs;
1041 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
1042 return 0;
1043}
1044
Paul Cercueile3fbd952014-03-11 16:58:33 +01001045static int add_attr_to_channel(struct iio_channel *chn,
1046 const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001047{
Paul Cercueilb34e0222014-05-05 15:32:38 +02001048 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001049 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001050 if (!name)
1051 return -ENOMEM;
1052
Paul Cercueile3fbd952014-03-11 16:58:33 +01001053 fn = strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +01001054 if (!fn)
1055 goto err_free_name;
1056
Paul Cercueilb34e0222014-05-05 15:32:38 +02001057 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
1058 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +01001059 if (!attrs)
1060 goto err_free_fn;
1061
Paul Cercueil42d12352014-05-05 16:11:58 +02001062 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +02001063 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001064 chn->attrs = attrs;
1065 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
1066 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +01001067
Paul Cercueil167d3112014-02-18 12:23:53 +01001068err_free_fn:
1069 free(fn);
1070err_free_name:
1071 free(name);
1072 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001073}
1074
1075static int add_channel_to_device(struct iio_device *dev,
1076 struct iio_channel *chn)
1077{
1078 struct iio_channel **channels = realloc(dev->channels,
1079 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
1080 if (!channels)
1081 return -ENOMEM;
1082
1083 channels[dev->nb_channels++] = chn;
1084 dev->channels = channels;
1085 DEBUG("Added channel \'%s\' to device \'%s\'\n", chn->id, dev->id);
1086 return 0;
1087}
1088
1089static int add_device_to_context(struct iio_context *ctx,
1090 struct iio_device *dev)
1091{
1092 struct iio_device **devices = realloc(ctx->devices,
1093 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
1094 if (!devices)
1095 return -ENOMEM;
1096
1097 devices[ctx->nb_devices++] = dev;
1098 ctx->devices = devices;
1099 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
1100 return 0;
1101}
1102
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001103static struct iio_channel *create_channel(struct iio_device *dev,
1104 char *id, const char *attr, const char *path)
1105{
1106 struct iio_channel *chn = calloc(1, sizeof(*chn));
1107 if (!chn)
1108 return NULL;
1109
1110 if (!strncmp(attr, "out_", 4))
1111 chn->is_output = true;
1112 else if (strncmp(attr, "in_", 3))
1113 goto err_free_chn;
1114
1115 chn->dev = dev;
1116 chn->id = id;
1117
1118 if (!add_attr_to_channel(chn, attr, path))
1119 return chn;
1120
1121err_free_chn:
1122 free(chn);
1123 return NULL;
1124}
1125
1126static int add_channel(struct iio_device *dev, const char *name,
1127 const char *path, bool dir_is_scan_elements)
1128{
1129 struct iio_channel *chn;
1130 char *channel_id;
1131 unsigned int i;
1132 int ret;
1133
1134 channel_id = get_channel_id(name);
1135 if (!channel_id)
1136 return -ENOMEM;
1137
1138 for (i = 0; i < dev->nb_channels; i++) {
1139 chn = dev->channels[i];
1140 if (!strcmp(chn->id, channel_id)
1141 && chn->is_output == (name[0] == 'o')) {
1142 free(channel_id);
1143 ret = add_attr_to_channel(chn, name, path);
1144 chn->is_scan_element = dir_is_scan_elements && !ret;
1145 return ret;
1146 }
1147 }
1148
1149 chn = create_channel(dev, channel_id, name, path);
1150 if (!chn) {
1151 free(channel_id);
1152 return -ENXIO;
1153 }
1154 ret = add_channel_to_device(dev, chn);
1155 if (ret)
1156 free_channel(chn);
1157 else
1158 chn->is_scan_element = dir_is_scan_elements;
1159 return ret;
1160}
1161
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001162/*
1163 * Possible return values:
1164 * 0 = Attribute should not be moved to the channel
1165 * 1 = Attribute should be moved to the channel and it is a shared attribute
1166 * 2 = Attribute should be moved to the channel and it is a private attribute
1167 */
1168static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001169{
1170 unsigned int i, len;
1171 char *ptr;
1172
Paul Cercueil35a01312014-02-20 10:56:57 +01001173 if (!chn->is_output && !strncmp(attr, "in_", 3))
1174 attr += 3;
1175 else if (chn->is_output && !strncmp(attr, "out_", 4))
1176 attr += 4;
1177 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001178 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001179
1180 ptr = strchr(attr, '_');
1181 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001182 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001183
1184 len = ptr - attr;
1185
1186 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001187 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001188
1189 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001190 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1191 if (chn->name) {
1192 size_t name_len = strlen(chn->name);
1193 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1194 attr[len + 1 + name_len] == '_')
1195 return 2;
1196 }
1197 return 1;
1198 } else if (chn->id[len] != '_') {
1199 return 0;
1200 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001201
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001202 if (find_modifier(chn->id + len + 1, NULL) != IIO_NO_MOD)
1203 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001204
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001205 return 0;
1206}
1207
1208static int detect_global_attr(struct iio_device *dev, const char *attr,
1209 unsigned int level, bool *match)
1210{
1211 unsigned int i;
1212
1213 *match = false;
1214 for (i = 0; i < dev->nb_channels; i++) {
1215 struct iio_channel *chn = dev->channels[i];
1216 if (is_global_attr(chn, attr) == level) {
1217 int ret;
1218 *match = true;
1219 ret = add_attr_to_channel(chn, attr, attr);
1220 if (ret)
1221 return ret;
1222 }
1223 }
1224
1225 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001226}
1227
1228static int detect_and_move_global_attrs(struct iio_device *dev)
1229{
1230 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001231 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001232
1233 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001234 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001235 bool match;
1236 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001237
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001238 ret = detect_global_attr(dev, attr, 2, &match);
1239 if (ret)
1240 return ret;
1241
1242 if (!match) {
1243 ret = detect_global_attr(dev, attr, 1, &match);
1244 if (ret)
1245 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001246 }
1247
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001248 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001249 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001250 dev->attrs[i] = NULL;
1251 }
1252 }
1253
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001254 /* Find channels without an index */
1255 for (i = 0; i < dev->nb_attrs; i++) {
1256 const char *attr = dev->attrs[i];
1257 bool match;
1258 int ret;
1259
1260 if (!dev->attrs[i])
1261 continue;
1262
1263 if (is_channel(attr, false)) {
1264 ret = add_channel(dev, attr, attr, false);
1265 if (ret)
1266 return ret;
1267
1268 free(dev->attrs[i]);
1269 dev->attrs[i] = NULL;
1270 }
1271 }
1272
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001273 for (i = 0; i < dev->nb_attrs; i++) {
1274 if (dev->attrs[i])
1275 *ptr++ = dev->attrs[i];
1276 }
1277
1278 dev->nb_attrs = ptr - dev->attrs;
1279 return 0;
1280}
1281
Paul Cercueile3fbd952014-03-11 16:58:33 +01001282static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001283 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001284{
Paul Cercueil1be57832014-03-11 16:27:16 +01001285 int ret;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001286 char buf[1024];
Paul Cercueil1be57832014-03-11 16:27:16 +01001287 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001288
1289 if (dir_is_scan_elements) {
1290 snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001291 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001292 } else {
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001293 if (!is_channel(name, true))
1294 return add_attr_to_device(dev, name);
Paul Cercueila91358e2014-04-24 16:40:19 +02001295 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001296 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001297
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001298 return add_channel(dev, name, path, dir_is_scan_elements);
Paul Cercueil1be57832014-03-11 16:27:16 +01001299}
1300
Paul Cercueile3fbd952014-03-11 16:58:33 +01001301static int add_attr_or_channel(void *d, const char *path)
1302{
Paul Cercueila91358e2014-04-24 16:40:19 +02001303 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001304}
1305
1306static int add_scan_element(void *d, const char *path)
1307{
Paul Cercueila91358e2014-04-24 16:40:19 +02001308 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001309}
1310
Paul Cercueil1be57832014-03-11 16:27:16 +01001311static int foreach_in_dir(void *d, const char *path, bool is_dir,
1312 int (*callback)(void *, const char *))
1313{
1314 long name_max;
1315 struct dirent *entry, *result;
1316 DIR *dir = opendir(path);
1317 if (!dir)
1318 return -errno;
1319
1320 name_max = pathconf(path, _PC_NAME_MAX);
1321 if (name_max == -1)
1322 name_max = 255;
1323 entry = malloc(offsetof(struct dirent, d_name) + name_max + 1);
1324 if (!entry) {
1325 closedir(dir);
1326 return -ENOMEM;
1327 }
1328
1329 while (true) {
1330 struct stat st;
1331 char buf[1024];
1332 int ret = readdir_r(dir, entry, &result);
1333 if (ret) {
Paul Cercueil87b988f2015-05-22 10:57:32 +02001334 iio_strerror(ret, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001335 ERROR("Unable to open directory %s: %s\n", path, buf);
1336 free(entry);
1337 closedir(dir);
Paul Cercueilc57da332015-03-16 17:09:48 +01001338 return -ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001339 }
1340 if (!result)
1341 break;
1342
1343 snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
1344 if (stat(buf, &st) < 0) {
1345 ret = -errno;
Paul Cercueil87b988f2015-05-22 10:57:32 +02001346 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001347 ERROR("Unable to stat file: %s\n", buf);
1348 free(entry);
1349 closedir(dir);
1350 return ret;
1351 }
1352
1353 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1354 ret = callback(d, buf);
1355 else if (!is_dir && S_ISREG(st.st_mode))
1356 ret = callback(d, buf);
1357 else
1358 continue;
1359
1360 if (ret < 0) {
1361 free(entry);
1362 closedir(dir);
1363 return ret;
1364 }
1365 }
1366
1367 free(entry);
1368 closedir(dir);
1369 return 0;
1370}
1371
Paul Cercueile3fbd952014-03-11 16:58:33 +01001372static int add_scan_elements(struct iio_device *dev, const char *devpath)
1373{
1374 struct stat st;
1375 char buf[1024];
1376 snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
1377
1378 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1379 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1380 if (ret < 0)
1381 return ret;
1382 }
1383
1384 return 0;
1385}
1386
Paul Cercueil1be57832014-03-11 16:27:16 +01001387static int create_device(void *d, const char *path)
1388{
Paul Cercueilff778232014-03-24 14:23:08 +01001389 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001390 unsigned int i;
1391 int ret;
1392 struct iio_context *ctx = d;
1393 struct iio_device *dev = calloc(1, sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001394 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001395 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001396
Paul Cercueileaab6582014-02-21 09:35:59 +01001397 dev->pdata = calloc(1, sizeof(*dev->pdata));
1398 if (!dev->pdata) {
1399 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001400 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001401 }
1402
Romain Roffé6ce74a22015-06-30 11:45:11 +02001403 dev->pdata->fd = -1;
Romain Roffécead1da2015-06-30 13:35:51 +02001404 dev->pdata->blocking = true;
Romain Roffé0f737472015-06-30 16:45:54 +02001405 dev->pdata->nb_blocks = NB_BLOCKS;
Romain Roffé6ce74a22015-06-30 11:45:11 +02001406
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001407 dev->ctx = ctx;
Paul Cercueil1be57832014-03-11 16:27:16 +01001408 dev->id = strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001409 if (!dev->id) {
Romain Roffé0f737472015-06-30 16:45:54 +02001410 local_free_pdata(dev);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001411 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001412 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001413 }
1414
Paul Cercueil1be57832014-03-11 16:27:16 +01001415 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
1416 if (ret < 0) {
1417 free_device(dev);
1418 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001419 }
1420
Michael Hennerichebe49662014-11-07 10:32:44 +01001421 ret = add_scan_elements(dev, path);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001422 if (ret < 0) {
1423 free_device(dev);
1424 return ret;
1425 }
1426
Paul Cercueilbab69a92015-07-03 11:24:17 +02001427 for (i = 0; i < dev->nb_channels; i++)
1428 set_channel_name(dev->channels[i]);
1429
Michael Hennerichebe49662014-11-07 10:32:44 +01001430 ret = detect_and_move_global_attrs(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001431 if (ret < 0) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001432 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001433 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001434 }
1435
Paul Cercueilff778232014-03-24 14:23:08 +01001436 dev->words = (dev->nb_channels + 31) / 32;
1437 if (dev->words) {
1438 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001439 if (!mask) {
1440 free_device(dev);
1441 return ret;
1442 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001443 }
1444
Paul Cercueilff778232014-03-24 14:23:08 +01001445 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001446
Paul Cercueil1be57832014-03-11 16:27:16 +01001447 ret = add_device_to_context(ctx, dev);
1448 if (ret < 0)
1449 free_device(dev);
1450 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001451}
1452
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001453static int add_debug_attr(void *d, const char *path)
1454{
1455 struct iio_device *dev = d;
1456 const char *attr = strrchr(path, '/') + 1;
1457 char **attrs, *name = strdup(attr);
1458 if (!name)
1459 return -ENOMEM;
1460
1461 attrs = realloc(dev->debug_attrs,
1462 (1 + dev->nb_debug_attrs) * sizeof(char *));
1463 if (!attrs) {
1464 free(name);
1465 return -ENOMEM;
1466 }
1467
1468 attrs[dev->nb_debug_attrs++] = name;
1469 dev->debug_attrs = attrs;
1470 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1471 return 0;
1472}
1473
1474static int add_debug(void *d, const char *path)
1475{
1476 struct iio_context *ctx = d;
1477 const char *name = strrchr(path, '/') + 1;
1478 struct iio_device *dev = iio_context_find_device(ctx, name);
1479 if (!dev)
1480 return -ENODEV;
1481 else
1482 return foreach_in_dir(dev, path, false, add_debug_attr);
1483}
1484
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001485static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1486{
1487 ctx->rw_timeout_ms = timeout;
1488 return 0;
1489}
1490
Paul Cercueil0865e802014-10-28 14:35:19 +01001491static struct iio_context * local_clone(
1492 const struct iio_context *ctx __attribute__((unused)))
1493{
Paul Cercueil63e52182014-12-11 12:52:48 +01001494 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001495}
1496
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001497static const struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001498 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001499 .open = local_open,
1500 .close = local_close,
Romain Roffé87897862015-06-30 13:34:08 +02001501 .get_fd = local_get_fd,
Romain Roffécead1da2015-06-30 13:35:51 +02001502 .set_blocking_mode = local_set_blocking_mode,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001503 .read = local_read,
1504 .write = local_write,
Romain Roffé0f737472015-06-30 16:45:54 +02001505 .set_kernel_buffers_count = local_set_kernel_buffers_count,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001506 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001507 .read_device_attr = local_read_dev_attr,
1508 .write_device_attr = local_write_dev_attr,
1509 .read_channel_attr = local_read_chn_attr,
1510 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001511 .get_trigger = local_get_trigger,
1512 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001513 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001514 .set_timeout = local_set_timeout,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001515};
1516
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001517static void init_index(struct iio_channel *chn)
1518{
1519 char buf[1024];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001520 long id = -ENOENT;
1521
1522 if (chn->is_scan_element) {
1523 id = (long) local_read_chn_attr(chn, "index", buf, sizeof(buf));
1524 if (id > 0)
1525 id = atol(buf);
1526 }
1527 chn->index = id;
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001528}
1529
1530static void init_data_format(struct iio_channel *chn)
1531{
1532 char buf[1024];
1533 ssize_t ret;
1534
1535 if (chn->is_scan_element) {
1536 ret = local_read_chn_attr(chn, "type", buf, sizeof(buf));
1537 if (ret < 0) {
1538 chn->format.length = 0;
1539 } else {
1540 char endian, sign;
1541
1542 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
1543 &chn->format.bits, &chn->format.length,
1544 &chn->format.shift);
Michael Hennerichfa3c6f62014-08-13 11:21:23 +02001545 chn->format.is_signed = (sign == 's' || sign == 'S');
1546 chn->format.is_fully_defined =
1547 (sign == 'S' || sign == 'U'||
1548 chn->format.bits == chn->format.length);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001549 chn->format.is_be = endian == 'b';
1550 }
1551 }
1552
1553 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1554 if (ret < 0) {
1555 chn->format.with_scale = false;
1556 } else {
1557 chn->format.with_scale = true;
1558 chn->format.scale = atof(buf);
1559 }
1560}
1561
1562static void init_scan_elements(struct iio_context *ctx)
1563{
1564 unsigned int i, j;
1565
1566 for (i = 0; i < ctx->nb_devices; i++) {
1567 struct iio_device *dev = ctx->devices[i];
1568
1569 for (j = 0; j < dev->nb_channels; j++) {
1570 struct iio_channel *chn = dev->channels[j];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001571 init_index(chn);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001572 init_data_format(chn);
1573 }
1574 }
1575}
1576
Paul Cercueil63e52182014-12-11 12:52:48 +01001577struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001578{
Paul Cercueilfd387472015-08-05 10:34:19 +02001579 int ret = -ENOMEM;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001580 unsigned int len;
1581 struct utsname uts;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001582 struct iio_context *ctx = calloc(1, sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001583 if (!ctx)
Paul Cercueilfd387472015-08-05 10:34:19 +02001584 goto err_set_errno;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001585
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001586 ctx->ops = &local_ops;
1587 ctx->name = "local";
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001588 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001589
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001590 uname(&uts);
1591 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
1592 + strlen(uts.version) + strlen(uts.machine);
1593 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
1594 if (!ctx->description) {
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001595 free(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001596 goto err_set_errno;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001597 }
1598
1599 snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
1600 uts.nodename, uts.release, uts.version, uts.machine);
1601
Paul Cercueil1be57832014-03-11 16:27:16 +01001602 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
Paul Cercueilfd387472015-08-05 10:34:19 +02001603 if (ret < 0)
1604 goto err_context_destroy;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001605
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001606 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001607
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001608 init_scan_elements(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001609 ret = iio_context_init(ctx);
1610 if (ret < 0)
1611 goto err_context_destroy;
Paul Cercueilae88fde2014-03-12 11:47:10 +01001612
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001613 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001614
Paul Cercueilfd387472015-08-05 10:34:19 +02001615err_context_destroy:
1616 iio_context_destroy(ctx);
1617err_set_errno:
1618 errno = -ret;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001619 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001620}