blob: ec48c7e45065bd4d9acb27b5a622896c59478f38 [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 Cercueil3dad0482016-02-04 11:40:32 +0100215static int device_check_ready(const struct iio_device *dev, short events)
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200216{
217 struct pollfd pollfd = {
Romain Roffé6ce74a22015-06-30 11:45:11 +0200218 .fd = dev->pdata->fd,
Paul Cercueil3dad0482016-02-04 11:40:32 +0100219 .events = events,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200220 };
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;
Paul Cercueil3dad0482016-02-04 11:40:32 +0100233 if (!(pollfd.revents & events))
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200234 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
Paul Cercueil3dad0482016-02-04 11:40:32 +0100327 ret = device_check_ready(dev, POLLIN);
Lars-Peter Clausen666cfe52014-07-14 11:43:15 +0200328 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 Cercueil3dad0482016-02-04 11:40:32 +0100353 ret = device_check_ready(dev, POLLOUT);
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200354 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) {
Paul Cercueil3dad0482016-02-04 11:40:32 +0100369 ret = device_check_ready(dev, POLLOUT);
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200370 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 Cercueil3dad0482016-02-04 11:40:32 +0100408 ret = (ssize_t) device_check_ready(dev, POLLIN | POLLOUT);
409 if (ret < 0)
410 return ret;
411
Paul Cercueil92f46df2014-04-28 13:17:53 +0200412 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200413 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200414
415 if (pdata->cyclic) {
416 if (pdata->cyclic_buffer_enqueued)
417 return -EBUSY;
418 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
419 pdata->cyclic_buffer_enqueued = true;
420 }
421
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200422 last_block->bytes_used = bytes_used;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200423 ret = (ssize_t) ioctl(f,
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200424 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200425 if (ret) {
426 ret = (ssize_t) -errno;
427 ERROR("Unable to enqueue block: %s\n", strerror(errno));
428 return ret;
429 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200430
431 if (pdata->cyclic) {
432 *addr_ptr = pdata->addrs[pdata->last_dequeued];
433 return (ssize_t) last_block->bytes_used;
434 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200435 }
436
Nicholas Pillitteric65095d2015-05-18 20:11:47 -0400437 memset(&block, 0, sizeof(block));
Romain Roffé6ce74a22015-06-30 11:45:11 +0200438 ret = (ssize_t) ioctl(f, BLOCK_DEQUEUE_IOCTL, &block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200439 if (ret) {
440 ret = (ssize_t) -errno;
441 ERROR("Unable to dequeue block: %s\n", strerror(errno));
442 return ret;
443 }
444
Paul Cercueil558ade42014-11-27 10:59:48 +0100445 /* Requested buffer size is too big! */
446 if (pdata->last_dequeued < 0 && bytes_used != block.size)
447 return -EFBIG;
448
Paul Cercueil92f46df2014-04-28 13:17:53 +0200449 pdata->last_dequeued = block.id;
450 *addr_ptr = pdata->addrs[block.id];
451 return (ssize_t) block.bytes_used;
452}
453
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200454static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
455 char *dst, size_t len, bool is_debug)
456{
457 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
458 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
459 char *ptr = dst;
460
461 for (i = 0; len >= 4 && i < nb; i++) {
462 /* Recursive! */
463 ssize_t ret = local_read_dev_attr(dev, attrs[i],
464 ptr + 4, len - 4, is_debug);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200465 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200466
467 /* Align the length to 4 bytes */
468 if (ret > 0 && ret & 3)
469 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200470 ptr += 4 + (ret < 0 ? 0 : ret);
471 len -= 4 + (ret < 0 ? 0 : ret);
472 }
473
474 return ptr - dst;
475}
476
477static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
478 char *dst, size_t len)
479{
480 unsigned int i;
481 char *ptr = dst;
482
483 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
484 /* Recursive! */
485 ssize_t ret = local_read_chn_attr(chn,
486 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200487 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200488
489 /* Align the length to 4 bytes */
490 if (ret > 0 && ret & 3)
491 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200492 ptr += 4 + (ret < 0 ? 0 : ret);
493 len -= 4 + (ret < 0 ? 0 : ret);
494 }
495
496 return ptr - dst;
497}
498
Paul Cercueil1da28122014-05-22 10:59:49 +0200499static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
500{
501 while (nb--) {
502 int32_t val;
503
504 if (len < 4)
505 return -EINVAL;
506
507 val = (int32_t) ntohl(*(uint32_t *) src);
508 src += 4;
509 len -= 4;
510
511 if (val > 0) {
512 if ((uint32_t) val > len)
513 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200514
515 /* Align the length to 4 bytes */
516 if (val & 3)
517 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200518 len -= val;
519 src += val;
520 }
521 }
522
523 /* We should have analyzed the whole buffer by now */
524 return !len ? 0 : -EINVAL;
525}
526
527static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
528 const char *src, size_t len, bool is_debug)
529{
530 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
531 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
532 const char *ptr = src;
533
534 /* First step: Verify that the buffer is in the correct format */
535 if (local_buffer_analyze(nb, src, len))
536 return -EINVAL;
537
538 /* Second step: write the attributes */
539 for (i = 0; i < nb; i++) {
540 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
541 ptr += 4;
542
543 if (val > 0) {
544 local_write_dev_attr(dev, attrs[i], ptr, val, is_debug);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200545
546 /* Align the length to 4 bytes */
547 if (val & 3)
548 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200549 ptr += val;
550 }
551 }
552
553 return ptr - src;
554}
555
556static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
557 const char *src, size_t len)
558{
559 unsigned int i, nb = chn->nb_attrs;
560 const char *ptr = src;
561
562 /* First step: Verify that the buffer is in the correct format */
563 if (local_buffer_analyze(nb, src, len))
564 return -EINVAL;
565
566 /* Second step: write the attributes */
567 for (i = 0; i < nb; i++) {
568 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
569 ptr += 4;
570
571 if (val > 0) {
572 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200573
574 /* Align the length to 4 bytes */
575 if (val & 3)
576 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200577 ptr += val;
578 }
579 }
580
581 return ptr - src;
582}
583
Paul Cercueil167d3112014-02-18 12:23:53 +0100584static ssize_t local_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200585 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100586{
Paul Cercueil3e898302014-02-17 16:17:11 +0100587 FILE *f;
588 char buf[1024];
589 ssize_t ret;
590
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200591 if (!attr)
592 return local_read_all_dev_attrs(dev, dst, len, is_debug);
593
Paul Cercueil50c762a2014-04-14 15:55:43 +0200594 if (is_debug)
595 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
596 dev->id, attr);
597 else
598 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
599 dev->id, attr);
Paul Cercueil3e898302014-02-17 16:17:11 +0100600 f = fopen(buf, "r");
601 if (!f)
602 return -errno;
603
604 ret = fread(dst, 1, len, f);
605 if (ret > 0)
606 dst[ret - 1] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100607 fflush(f);
608 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200609 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100610 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200611 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100612}
613
Paul Cercueil167d3112014-02-18 12:23:53 +0100614static ssize_t local_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200615 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100616{
Paul Cercueil3e898302014-02-17 16:17:11 +0100617 FILE *f;
618 char buf[1024];
619 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100620
Paul Cercueil1da28122014-05-22 10:59:49 +0200621 if (!attr)
622 return local_write_all_dev_attrs(dev, src, len, is_debug);
623
Paul Cercueil50c762a2014-04-14 15:55:43 +0200624 if (is_debug)
625 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
626 dev->id, attr);
627 else
628 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
629 dev->id, attr);
Andrea Galbusera7f83b832014-07-25 18:23:36 +0200630 f = fopen(buf, "w");
Paul Cercueil3e898302014-02-17 16:17:11 +0100631 if (!f)
632 return -errno;
633
634 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100635 fflush(f);
636 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200637 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100638 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200639 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100640}
641
Paul Cercueil167d3112014-02-18 12:23:53 +0100642static const char * get_filename(const struct iio_channel *chn,
643 const char *attr)
644{
Paul Cercueil167d3112014-02-18 12:23:53 +0100645 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200646 for (i = 0; i < chn->nb_attrs; i++)
647 if (!strcmp(attr, chn->attrs[i].name))
648 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100649 return attr;
650}
651
652static ssize_t local_read_chn_attr(const struct iio_channel *chn,
653 const char *attr, char *dst, size_t len)
654{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200655 if (!attr)
656 return local_read_all_chn_attrs(chn, dst, len);
657
Paul Cercueil167d3112014-02-18 12:23:53 +0100658 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200659 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100660}
661
662static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200663 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100664{
Paul Cercueil1da28122014-05-22 10:59:49 +0200665 if (!attr)
666 return local_write_all_chn_attrs(chn, src, len);
667
Paul Cercueil167d3112014-02-18 12:23:53 +0100668 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200669 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100670}
671
Paul Cercueilff778232014-03-24 14:23:08 +0100672static int channel_write_state(const struct iio_channel *chn)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100673{
Paul Cercueilff778232014-03-24 14:23:08 +0100674 char *en = iio_channel_is_enabled(chn) ? "1" : "0";
Paul Cercueilcecda352014-05-06 18:14:29 +0200675 ssize_t ret = local_write_chn_attr(chn, "en", en, 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100676 if (ret < 0)
677 return (int) ret;
678 else
679 return 0;
680}
681
Paul Cercueil92f46df2014-04-28 13:17:53 +0200682static int enable_high_speed(const struct iio_device *dev)
683{
684 struct block_alloc_req req;
685 struct iio_device_pdata *pdata = dev->pdata;
686 unsigned int i;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200687 int ret, fd = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200688
Paul Cercueil71694c72014-05-22 14:02:13 +0200689 if (pdata->cyclic) {
690 pdata->nb_blocks = 1;
691 DEBUG("Enabling cyclic mode\n");
692 } else {
Paul Cercueil71694c72014-05-22 14:02:13 +0200693 DEBUG("Cyclic mode not enabled\n");
694 }
695
Romain Roffé0f737472015-06-30 16:45:54 +0200696 pdata->blocks = calloc(pdata->nb_blocks, sizeof(*pdata->blocks));
697 if (!pdata->blocks) {
698 pdata->nb_blocks = 0;
699 return -ENOMEM;
700 }
701
702 pdata->addrs = calloc(pdata->nb_blocks, sizeof(*pdata->addrs));
703 if (!pdata->addrs) {
704 free(pdata->blocks);
705 pdata->blocks = NULL;
706 return -ENOMEM;
707 }
708
Paul Cercueil1fa913d2015-04-28 16:30:53 +0200709 req.id = 0;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200710 req.type = 0;
711 req.size = pdata->samples_count *
712 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Paul Cercueil71694c72014-05-22 14:02:13 +0200713 req.count = pdata->nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200714
715 ret = ioctl(fd, BLOCK_ALLOC_IOCTL, &req);
Romain Roffé0f737472015-06-30 16:45:54 +0200716 if (ret < 0) {
717 ret = -errno;
718 goto err_freemem;
719 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200720
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200721 /* We might get less blocks than what we asked for */
722 pdata->nb_blocks = req.count;
723
Paul Cercueil92f46df2014-04-28 13:17:53 +0200724 /* mmap all the blocks */
Paul Cercueil71694c72014-05-22 14:02:13 +0200725 for (i = 0; i < pdata->nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200726 pdata->blocks[i].id = i;
727 ret = ioctl(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
728 if (ret) {
729 ret = -errno;
730 goto err_munmap;
731 }
732
733 ret = ioctl(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
734 if (ret) {
735 ret = -errno;
736 goto err_munmap;
737 }
738
Paul Cercueil032a5652014-05-12 17:11:19 +0200739 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
740 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200741 MAP_SHARED, fd, pdata->blocks[i].offset);
742 if (pdata->addrs[i] == MAP_FAILED) {
743 ret = -errno;
744 goto err_munmap;
745 }
746 }
747
Paul Cercueil4a702d32014-05-12 17:02:37 +0200748 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200749 return 0;
750
751err_munmap:
752 for (; i > 0; i--)
753 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
754 ioctl(fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200755err_freemem:
756 free(pdata->addrs);
757 pdata->addrs = NULL;
758 free(pdata->blocks);
759 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200760 return ret;
761}
762
Paul Cercueil92f15c22015-04-20 11:36:51 +0200763static int local_open(const struct iio_device *dev,
764 size_t samples_count, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100765{
766 unsigned int i;
767 int ret;
768 char buf[1024];
769 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200770
Romain Roffé6ce74a22015-06-30 11:45:11 +0200771 if (pdata->fd != -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100772 return -EBUSY;
773
Paul Cercueilcecda352014-05-06 18:14:29 +0200774 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200775 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100776 return ret;
777
Paul Cercueil11334342015-06-23 16:55:35 +0200778 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200779 ret = local_write_dev_attr(dev, "buffer/length",
780 buf, strlen(buf) + 1, false);
781 if (ret < 0)
782 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200783
Paul Cercueil8c29e412014-04-07 09:46:45 +0200784 snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200785 pdata->fd = open(buf, O_RDWR);
786 if (pdata->fd == -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100787 return -errno;
788
Paul Cercueil11334342015-06-23 16:55:35 +0200789 /* Disable channels */
790 for (i = 0; i < dev->nb_channels; i++) {
791 struct iio_channel *chn = dev->channels[i];
792 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
793 ret = channel_write_state(chn);
794 if (ret < 0)
795 goto err_close;
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100796 }
Paul Cercueil11334342015-06-23 16:55:35 +0200797 }
798 /* Enable channels */
799 for (i = 0; i < dev->nb_channels; i++) {
800 struct iio_channel *chn = dev->channels[i];
801 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
802 ret = channel_write_state(chn);
803 if (ret < 0)
804 goto err_close;
Paul Cercueile1311222014-03-12 15:46:16 +0100805 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100806 }
807
Paul Cercueil71694c72014-05-22 14:02:13 +0200808 pdata->cyclic = cyclic;
809 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200810 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200811 pdata->samples_count = samples_count;
Paul Cercueil71694c72014-05-22 14:02:13 +0200812 pdata->is_high_speed = !enable_high_speed(dev);
Paul Cercueilb762fc62014-05-12 16:56:09 +0200813
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200814 if (!pdata->is_high_speed) {
Romain Roffé0f737472015-06-30 16:45:54 +0200815 unsigned long size = samples_count * pdata->nb_blocks;
Paul Cercueil032a5652014-05-12 17:11:19 +0200816 WARNING("High-speed mode not enabled\n");
Paul Cercueiled621ee2015-06-24 10:50:21 +0200817
818 /* Increase the size of the kernel buffer, when using the
819 * low-speed interface. This avoids losing samples when
820 * refilling the iio_buffer. */
Romain Roffé0f737472015-06-30 16:45:54 +0200821 snprintf(buf, sizeof(buf), "%lu", size);
Paul Cercueiled621ee2015-06-24 10:50:21 +0200822 ret = local_write_dev_attr(dev, "buffer/length",
823 buf, strlen(buf) + 1, false);
824 if (ret < 0)
825 goto err_close;
826
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200827 /* NOTE: The low-speed interface will enable the buffer after
Romain Roffécead1da2015-06-30 13:35:51 +0200828 * the first samples are written, or if the device is set
829 * to non blocking-mode */
Paul Cercueiled621ee2015-06-24 10:50:21 +0200830 } else {
Romain Roffécead1da2015-06-30 13:35:51 +0200831 ret = local_enable_buffer(dev);
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200832 if (ret < 0)
833 goto err_close;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200834 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100835
Paul Cercueil45c575d2014-03-20 15:14:01 +0100836 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +0100837err_close:
Romain Roffé6ce74a22015-06-30 11:45:11 +0200838 close(pdata->fd);
839 pdata->fd = -1;
Paul Cercueile1311222014-03-12 15:46:16 +0100840 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100841}
842
843static int local_close(const struct iio_device *dev)
844{
845 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100846 int ret;
847
Paul Cercueilb6a40c22015-07-02 11:12:16 +0200848 if (pdata->fd == -1)
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100849 return -EBADF;
850
Paul Cercueil92f46df2014-04-28 13:17:53 +0200851 if (pdata->is_high_speed) {
852 unsigned int i;
Paul Cercueil71694c72014-05-22 14:02:13 +0200853 for (i = 0; i < pdata->nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200854 munmap(pdata->addrs[i], pdata->blocks[i].size);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200855 ioctl(pdata->fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200856 free(pdata->addrs);
857 pdata->addrs = NULL;
858 free(pdata->blocks);
859 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200860 }
861
Romain Roffé6ce74a22015-06-30 11:45:11 +0200862 ret = close(pdata->fd);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100863 if (ret)
864 return ret;
865
Romain Roffé6ce74a22015-06-30 11:45:11 +0200866 pdata->fd = -1;
Paul Cercueil71694c72014-05-22 14:02:13 +0200867 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
868 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100869}
870
Romain Roffé87897862015-06-30 13:34:08 +0200871static int local_get_fd(const struct iio_device *dev)
872{
Paul Cercueil2cdc81b2015-07-02 11:13:23 +0200873 if (dev->pdata->fd == -1)
874 return -EBADF;
875 else
876 return dev->pdata->fd;
Romain Roffé87897862015-06-30 13:34:08 +0200877}
878
Romain Roffécead1da2015-06-30 13:35:51 +0200879static int local_set_blocking_mode(const struct iio_device *dev, bool blocking)
880{
881 int ret;
882
883 if (dev->pdata->fd == -1)
884 return -EBADF;
885
886 if (dev->pdata->cyclic)
887 return -EPERM;
888
889 ret = set_blocking_mode(dev->pdata->fd, blocking);
890 if (ret == 0) {
891 dev->pdata->blocking = blocking;
892
893 /* When a device is opened, it is configured in blocking mode.
894 * If the user wants to use the non blocking API, and poll the
895 * device to know when to make the first read, it is required to
896 * activate to buffer automatically when the device is switched
897 * in non-blocking mode. */
898 if (!blocking)
899 ret = local_enable_buffer(dev);
900 }
901
902 return ret;
903}
904
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100905static int local_get_trigger(const struct iio_device *dev,
906 const struct iio_device **trigger)
907{
908 char buf[1024];
909 unsigned int i;
910 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +0200911 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +0200912 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100913 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100914 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +0200915 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100916
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200917 if (buf[0] == '\0') {
918 *trigger = NULL;
919 return 0;
920 }
921
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100922 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +0200923 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100924 const struct iio_device *cur = dev->ctx->devices[i];
925 if (cur->name && !strcmp(cur->name, buf)) {
926 *trigger = cur;
927 return 0;
928 }
929 }
930 return -ENXIO;
931}
932
933static int local_set_trigger(const struct iio_device *dev,
934 const struct iio_device *trigger)
935{
936 ssize_t nb;
937 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +0200938 nb = local_write_dev_attr(dev, "trigger/current_trigger",
939 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100940 if (nb < 0)
941 return (int) nb;
942 else
943 return 0;
944}
945
Lars-Peter Clausend9806c22016-01-26 16:35:42 +0100946static bool is_channel(const char *attr, bool strict)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100947{
948 unsigned int i;
949 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +0100950 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
951 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100952 if (!strncmp(attr, "in_", 3))
953 ptr = strchr(attr + 3, '_');
954 else if (!strncmp(attr, "out_", 4))
955 ptr = strchr(attr + 4, '_');
956 if (!ptr)
957 return false;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +0100958 if (!strict)
959 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100960 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
961 return true;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100962
963 if (find_modifier(ptr + 1, NULL) != IIO_NO_MOD)
964 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100965 return false;
966}
967
968static char * get_channel_id(const char *attr)
969{
970 char *res, *ptr;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100971 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100972
973 attr = strchr(attr, '_') + 1;
974 ptr = strchr(attr, '_');
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100975 if (find_modifier(ptr + 1, &len) != IIO_NO_MOD)
976 ptr += len + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100977
978 res = malloc(ptr - attr + 1);
979 if (!res)
980 return NULL;
981
982 memcpy(res, attr, ptr - attr);
983 res[ptr - attr] = 0;
984 return res;
985}
986
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200987static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100988{
989 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100990 size_t len;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200991
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100992 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100993 if (find_modifier(ptr, &len) != IIO_NO_MOD)
994 ptr += len + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200995
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200996 if (chn->name) {
997 size_t len = strlen(chn->name);
998 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
999 ptr += len + 1;
1000 }
1001
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001002 return strdup(ptr);
1003}
1004
1005static int read_device_name(struct iio_device *dev)
1006{
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001007 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +02001008 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +01001009 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001010 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +01001011 else if (ret == 0)
1012 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001013
Paul Cercueil30430c72014-02-17 16:52:37 +01001014 dev->name = strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001015 if (!dev->name)
1016 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +01001017 else
1018 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001019}
1020
1021static int add_attr_to_device(struct iio_device *dev, const char *attr)
1022{
Paul Cercueilbb618272014-02-20 11:35:52 +01001023 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001024 unsigned int i;
1025
1026 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
1027 if (!strcmp(device_attrs_blacklist[i], attr))
1028 return 0;
1029
1030 if (!strcmp(attr, "name"))
1031 return read_device_name(dev);
1032
1033 name = strdup(attr);
1034 if (!name)
1035 return -ENOMEM;
1036
1037 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
1038 if (!attrs) {
1039 free(name);
1040 return -ENOMEM;
1041 }
1042
1043 attrs[dev->nb_attrs++] = name;
1044 dev->attrs = attrs;
1045 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
1046 return 0;
1047}
1048
Paul Cercueile3fbd952014-03-11 16:58:33 +01001049static int add_attr_to_channel(struct iio_channel *chn,
1050 const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001051{
Paul Cercueilb34e0222014-05-05 15:32:38 +02001052 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001053 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001054 if (!name)
1055 return -ENOMEM;
1056
Paul Cercueile3fbd952014-03-11 16:58:33 +01001057 fn = strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +01001058 if (!fn)
1059 goto err_free_name;
1060
Paul Cercueilb34e0222014-05-05 15:32:38 +02001061 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
1062 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +01001063 if (!attrs)
1064 goto err_free_fn;
1065
Paul Cercueil42d12352014-05-05 16:11:58 +02001066 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +02001067 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001068 chn->attrs = attrs;
1069 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
1070 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +01001071
Paul Cercueil167d3112014-02-18 12:23:53 +01001072err_free_fn:
1073 free(fn);
1074err_free_name:
1075 free(name);
1076 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001077}
1078
1079static int add_channel_to_device(struct iio_device *dev,
1080 struct iio_channel *chn)
1081{
1082 struct iio_channel **channels = realloc(dev->channels,
1083 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
1084 if (!channels)
1085 return -ENOMEM;
1086
1087 channels[dev->nb_channels++] = chn;
1088 dev->channels = channels;
1089 DEBUG("Added channel \'%s\' to device \'%s\'\n", chn->id, dev->id);
1090 return 0;
1091}
1092
1093static int add_device_to_context(struct iio_context *ctx,
1094 struct iio_device *dev)
1095{
1096 struct iio_device **devices = realloc(ctx->devices,
1097 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
1098 if (!devices)
1099 return -ENOMEM;
1100
1101 devices[ctx->nb_devices++] = dev;
1102 ctx->devices = devices;
1103 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
1104 return 0;
1105}
1106
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001107static struct iio_channel *create_channel(struct iio_device *dev,
1108 char *id, const char *attr, const char *path)
1109{
1110 struct iio_channel *chn = calloc(1, sizeof(*chn));
1111 if (!chn)
1112 return NULL;
1113
1114 if (!strncmp(attr, "out_", 4))
1115 chn->is_output = true;
1116 else if (strncmp(attr, "in_", 3))
1117 goto err_free_chn;
1118
1119 chn->dev = dev;
1120 chn->id = id;
1121
1122 if (!add_attr_to_channel(chn, attr, path))
1123 return chn;
1124
1125err_free_chn:
1126 free(chn);
1127 return NULL;
1128}
1129
1130static int add_channel(struct iio_device *dev, const char *name,
1131 const char *path, bool dir_is_scan_elements)
1132{
1133 struct iio_channel *chn;
1134 char *channel_id;
1135 unsigned int i;
1136 int ret;
1137
1138 channel_id = get_channel_id(name);
1139 if (!channel_id)
1140 return -ENOMEM;
1141
1142 for (i = 0; i < dev->nb_channels; i++) {
1143 chn = dev->channels[i];
1144 if (!strcmp(chn->id, channel_id)
1145 && chn->is_output == (name[0] == 'o')) {
1146 free(channel_id);
1147 ret = add_attr_to_channel(chn, name, path);
1148 chn->is_scan_element = dir_is_scan_elements && !ret;
1149 return ret;
1150 }
1151 }
1152
1153 chn = create_channel(dev, channel_id, name, path);
1154 if (!chn) {
1155 free(channel_id);
1156 return -ENXIO;
1157 }
1158 ret = add_channel_to_device(dev, chn);
1159 if (ret)
1160 free_channel(chn);
1161 else
1162 chn->is_scan_element = dir_is_scan_elements;
1163 return ret;
1164}
1165
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001166/*
1167 * Possible return values:
1168 * 0 = Attribute should not be moved to the channel
1169 * 1 = Attribute should be moved to the channel and it is a shared attribute
1170 * 2 = Attribute should be moved to the channel and it is a private attribute
1171 */
1172static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001173{
1174 unsigned int i, len;
1175 char *ptr;
1176
Paul Cercueil35a01312014-02-20 10:56:57 +01001177 if (!chn->is_output && !strncmp(attr, "in_", 3))
1178 attr += 3;
1179 else if (chn->is_output && !strncmp(attr, "out_", 4))
1180 attr += 4;
1181 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001182 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001183
1184 ptr = strchr(attr, '_');
1185 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001186 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001187
1188 len = ptr - attr;
1189
1190 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001191 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001192
1193 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001194 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1195 if (chn->name) {
1196 size_t name_len = strlen(chn->name);
1197 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1198 attr[len + 1 + name_len] == '_')
1199 return 2;
1200 }
1201 return 1;
1202 } else if (chn->id[len] != '_') {
1203 return 0;
1204 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001205
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001206 if (find_modifier(chn->id + len + 1, NULL) != IIO_NO_MOD)
1207 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001208
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001209 return 0;
1210}
1211
1212static int detect_global_attr(struct iio_device *dev, const char *attr,
1213 unsigned int level, bool *match)
1214{
1215 unsigned int i;
1216
1217 *match = false;
1218 for (i = 0; i < dev->nb_channels; i++) {
1219 struct iio_channel *chn = dev->channels[i];
1220 if (is_global_attr(chn, attr) == level) {
1221 int ret;
1222 *match = true;
1223 ret = add_attr_to_channel(chn, attr, attr);
1224 if (ret)
1225 return ret;
1226 }
1227 }
1228
1229 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001230}
1231
1232static int detect_and_move_global_attrs(struct iio_device *dev)
1233{
1234 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001235 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001236
1237 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001238 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001239 bool match;
1240 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001241
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001242 ret = detect_global_attr(dev, attr, 2, &match);
1243 if (ret)
1244 return ret;
1245
1246 if (!match) {
1247 ret = detect_global_attr(dev, attr, 1, &match);
1248 if (ret)
1249 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001250 }
1251
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001252 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001253 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001254 dev->attrs[i] = NULL;
1255 }
1256 }
1257
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001258 /* Find channels without an index */
1259 for (i = 0; i < dev->nb_attrs; i++) {
1260 const char *attr = dev->attrs[i];
1261 bool match;
1262 int ret;
1263
1264 if (!dev->attrs[i])
1265 continue;
1266
1267 if (is_channel(attr, false)) {
1268 ret = add_channel(dev, attr, attr, false);
1269 if (ret)
1270 return ret;
1271
1272 free(dev->attrs[i]);
1273 dev->attrs[i] = NULL;
1274 }
1275 }
1276
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001277 for (i = 0; i < dev->nb_attrs; i++) {
1278 if (dev->attrs[i])
1279 *ptr++ = dev->attrs[i];
1280 }
1281
1282 dev->nb_attrs = ptr - dev->attrs;
1283 return 0;
1284}
1285
Paul Cercueile3fbd952014-03-11 16:58:33 +01001286static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001287 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001288{
Paul Cercueil1be57832014-03-11 16:27:16 +01001289 int ret;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001290 char buf[1024];
Paul Cercueil1be57832014-03-11 16:27:16 +01001291 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001292
1293 if (dir_is_scan_elements) {
1294 snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001295 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001296 } else {
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001297 if (!is_channel(name, true))
1298 return add_attr_to_device(dev, name);
Paul Cercueila91358e2014-04-24 16:40:19 +02001299 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001300 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001301
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001302 return add_channel(dev, name, path, dir_is_scan_elements);
Paul Cercueil1be57832014-03-11 16:27:16 +01001303}
1304
Paul Cercueile3fbd952014-03-11 16:58:33 +01001305static int add_attr_or_channel(void *d, const char *path)
1306{
Paul Cercueila91358e2014-04-24 16:40:19 +02001307 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001308}
1309
1310static int add_scan_element(void *d, const char *path)
1311{
Paul Cercueila91358e2014-04-24 16:40:19 +02001312 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001313}
1314
Paul Cercueil1be57832014-03-11 16:27:16 +01001315static int foreach_in_dir(void *d, const char *path, bool is_dir,
1316 int (*callback)(void *, const char *))
1317{
1318 long name_max;
1319 struct dirent *entry, *result;
1320 DIR *dir = opendir(path);
1321 if (!dir)
1322 return -errno;
1323
1324 name_max = pathconf(path, _PC_NAME_MAX);
1325 if (name_max == -1)
1326 name_max = 255;
1327 entry = malloc(offsetof(struct dirent, d_name) + name_max + 1);
1328 if (!entry) {
1329 closedir(dir);
1330 return -ENOMEM;
1331 }
1332
1333 while (true) {
1334 struct stat st;
1335 char buf[1024];
1336 int ret = readdir_r(dir, entry, &result);
1337 if (ret) {
Paul Cercueil87b988f2015-05-22 10:57:32 +02001338 iio_strerror(ret, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001339 ERROR("Unable to open directory %s: %s\n", path, buf);
1340 free(entry);
1341 closedir(dir);
Paul Cercueilc57da332015-03-16 17:09:48 +01001342 return -ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001343 }
1344 if (!result)
1345 break;
1346
1347 snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
1348 if (stat(buf, &st) < 0) {
1349 ret = -errno;
Paul Cercueil87b988f2015-05-22 10:57:32 +02001350 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001351 ERROR("Unable to stat file: %s\n", buf);
1352 free(entry);
1353 closedir(dir);
1354 return ret;
1355 }
1356
1357 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1358 ret = callback(d, buf);
1359 else if (!is_dir && S_ISREG(st.st_mode))
1360 ret = callback(d, buf);
1361 else
1362 continue;
1363
1364 if (ret < 0) {
1365 free(entry);
1366 closedir(dir);
1367 return ret;
1368 }
1369 }
1370
1371 free(entry);
1372 closedir(dir);
1373 return 0;
1374}
1375
Paul Cercueile3fbd952014-03-11 16:58:33 +01001376static int add_scan_elements(struct iio_device *dev, const char *devpath)
1377{
1378 struct stat st;
1379 char buf[1024];
1380 snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
1381
1382 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1383 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1384 if (ret < 0)
1385 return ret;
1386 }
1387
1388 return 0;
1389}
1390
Paul Cercueil1be57832014-03-11 16:27:16 +01001391static int create_device(void *d, const char *path)
1392{
Paul Cercueilff778232014-03-24 14:23:08 +01001393 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001394 unsigned int i;
1395 int ret;
1396 struct iio_context *ctx = d;
1397 struct iio_device *dev = calloc(1, sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001398 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001399 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001400
Paul Cercueileaab6582014-02-21 09:35:59 +01001401 dev->pdata = calloc(1, sizeof(*dev->pdata));
1402 if (!dev->pdata) {
1403 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001404 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001405 }
1406
Romain Roffé6ce74a22015-06-30 11:45:11 +02001407 dev->pdata->fd = -1;
Romain Roffécead1da2015-06-30 13:35:51 +02001408 dev->pdata->blocking = true;
Romain Roffé0f737472015-06-30 16:45:54 +02001409 dev->pdata->nb_blocks = NB_BLOCKS;
Romain Roffé6ce74a22015-06-30 11:45:11 +02001410
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001411 dev->ctx = ctx;
Paul Cercueil1be57832014-03-11 16:27:16 +01001412 dev->id = strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001413 if (!dev->id) {
Romain Roffé0f737472015-06-30 16:45:54 +02001414 local_free_pdata(dev);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001415 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001416 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001417 }
1418
Paul Cercueil1be57832014-03-11 16:27:16 +01001419 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
1420 if (ret < 0) {
1421 free_device(dev);
1422 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001423 }
1424
Michael Hennerichebe49662014-11-07 10:32:44 +01001425 ret = add_scan_elements(dev, path);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001426 if (ret < 0) {
1427 free_device(dev);
1428 return ret;
1429 }
1430
Paul Cercueilbab69a92015-07-03 11:24:17 +02001431 for (i = 0; i < dev->nb_channels; i++)
1432 set_channel_name(dev->channels[i]);
1433
Michael Hennerichebe49662014-11-07 10:32:44 +01001434 ret = detect_and_move_global_attrs(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001435 if (ret < 0) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001436 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001437 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001438 }
1439
Paul Cercueilff778232014-03-24 14:23:08 +01001440 dev->words = (dev->nb_channels + 31) / 32;
1441 if (dev->words) {
1442 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001443 if (!mask) {
1444 free_device(dev);
1445 return ret;
1446 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001447 }
1448
Paul Cercueilff778232014-03-24 14:23:08 +01001449 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001450
Paul Cercueil1be57832014-03-11 16:27:16 +01001451 ret = add_device_to_context(ctx, dev);
1452 if (ret < 0)
1453 free_device(dev);
1454 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001455}
1456
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001457static int add_debug_attr(void *d, const char *path)
1458{
1459 struct iio_device *dev = d;
1460 const char *attr = strrchr(path, '/') + 1;
1461 char **attrs, *name = strdup(attr);
1462 if (!name)
1463 return -ENOMEM;
1464
1465 attrs = realloc(dev->debug_attrs,
1466 (1 + dev->nb_debug_attrs) * sizeof(char *));
1467 if (!attrs) {
1468 free(name);
1469 return -ENOMEM;
1470 }
1471
1472 attrs[dev->nb_debug_attrs++] = name;
1473 dev->debug_attrs = attrs;
1474 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1475 return 0;
1476}
1477
1478static int add_debug(void *d, const char *path)
1479{
1480 struct iio_context *ctx = d;
1481 const char *name = strrchr(path, '/') + 1;
1482 struct iio_device *dev = iio_context_find_device(ctx, name);
1483 if (!dev)
1484 return -ENODEV;
1485 else
1486 return foreach_in_dir(dev, path, false, add_debug_attr);
1487}
1488
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001489static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1490{
1491 ctx->rw_timeout_ms = timeout;
1492 return 0;
1493}
1494
Paul Cercueil0865e802014-10-28 14:35:19 +01001495static struct iio_context * local_clone(
1496 const struct iio_context *ctx __attribute__((unused)))
1497{
Paul Cercueil63e52182014-12-11 12:52:48 +01001498 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001499}
1500
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001501static const struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001502 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001503 .open = local_open,
1504 .close = local_close,
Romain Roffé87897862015-06-30 13:34:08 +02001505 .get_fd = local_get_fd,
Romain Roffécead1da2015-06-30 13:35:51 +02001506 .set_blocking_mode = local_set_blocking_mode,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001507 .read = local_read,
1508 .write = local_write,
Romain Roffé0f737472015-06-30 16:45:54 +02001509 .set_kernel_buffers_count = local_set_kernel_buffers_count,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001510 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001511 .read_device_attr = local_read_dev_attr,
1512 .write_device_attr = local_write_dev_attr,
1513 .read_channel_attr = local_read_chn_attr,
1514 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001515 .get_trigger = local_get_trigger,
1516 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001517 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001518 .set_timeout = local_set_timeout,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001519};
1520
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001521static void init_index(struct iio_channel *chn)
1522{
1523 char buf[1024];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001524 long id = -ENOENT;
1525
1526 if (chn->is_scan_element) {
1527 id = (long) local_read_chn_attr(chn, "index", buf, sizeof(buf));
1528 if (id > 0)
1529 id = atol(buf);
1530 }
1531 chn->index = id;
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001532}
1533
1534static void init_data_format(struct iio_channel *chn)
1535{
1536 char buf[1024];
1537 ssize_t ret;
1538
1539 if (chn->is_scan_element) {
1540 ret = local_read_chn_attr(chn, "type", buf, sizeof(buf));
1541 if (ret < 0) {
1542 chn->format.length = 0;
1543 } else {
1544 char endian, sign;
1545
1546 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
1547 &chn->format.bits, &chn->format.length,
1548 &chn->format.shift);
Michael Hennerichfa3c6f62014-08-13 11:21:23 +02001549 chn->format.is_signed = (sign == 's' || sign == 'S');
1550 chn->format.is_fully_defined =
1551 (sign == 'S' || sign == 'U'||
1552 chn->format.bits == chn->format.length);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001553 chn->format.is_be = endian == 'b';
1554 }
1555 }
1556
1557 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1558 if (ret < 0) {
1559 chn->format.with_scale = false;
1560 } else {
1561 chn->format.with_scale = true;
1562 chn->format.scale = atof(buf);
1563 }
1564}
1565
1566static void init_scan_elements(struct iio_context *ctx)
1567{
1568 unsigned int i, j;
1569
1570 for (i = 0; i < ctx->nb_devices; i++) {
1571 struct iio_device *dev = ctx->devices[i];
1572
1573 for (j = 0; j < dev->nb_channels; j++) {
1574 struct iio_channel *chn = dev->channels[j];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001575 init_index(chn);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001576 init_data_format(chn);
1577 }
1578 }
1579}
1580
Paul Cercueil63e52182014-12-11 12:52:48 +01001581struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001582{
Paul Cercueilfd387472015-08-05 10:34:19 +02001583 int ret = -ENOMEM;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001584 unsigned int len;
1585 struct utsname uts;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001586 struct iio_context *ctx = calloc(1, sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001587 if (!ctx)
Paul Cercueilfd387472015-08-05 10:34:19 +02001588 goto err_set_errno;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001589
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001590 ctx->ops = &local_ops;
1591 ctx->name = "local";
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001592 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001593
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001594 uname(&uts);
1595 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
1596 + strlen(uts.version) + strlen(uts.machine);
1597 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
1598 if (!ctx->description) {
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001599 free(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001600 goto err_set_errno;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001601 }
1602
1603 snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
1604 uts.nodename, uts.release, uts.version, uts.machine);
1605
Paul Cercueil1be57832014-03-11 16:27:16 +01001606 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
Paul Cercueilfd387472015-08-05 10:34:19 +02001607 if (ret < 0)
1608 goto err_context_destroy;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001609
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001610 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001611
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001612 init_scan_elements(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001613 ret = iio_context_init(ctx);
1614 if (ret < 0)
1615 goto err_context_destroy;
Paul Cercueilae88fde2014-03-12 11:47:10 +01001616
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001617 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001618
Paul Cercueilfd387472015-08-05 10:34:19 +02001619err_context_destroy:
1620 iio_context_destroy(ctx);
1621err_set_errno:
1622 errno = -ret;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001623 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001624}