blob: 9c999db1e3ccaad29a0fda009dc4e6854d80878c [file] [log] [blame]
Paul Cercueilbb4401d2014-02-28 16:10:49 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * */
18
Paul Cercueil0b2ce712014-02-17 15:04:18 +010019#include "debug.h"
20#include "iio-private.h"
21
Paul Cercueil1be57832014-03-11 16:27:16 +010022#include <dirent.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010023#include <errno.h>
Lars-Peter Clausenea5ea6f2016-04-21 18:23:38 +020024#include <limits.h>
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020025#include <poll.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010026#include <stdbool.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010027#include <stddef.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010028#include <stdio.h>
29#include <string.h>
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +020030#include <sys/eventfd.h>
Paul Cercueil92f46df2014-04-28 13:17:53 +020031#include <sys/ioctl.h>
32#include <sys/mman.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010033#include <sys/types.h>
34#include <sys/stat.h>
35#include <unistd.h>
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +020036#include <string.h>
Lars-Peter Clausen00f80092014-07-01 17:52:05 +020037#include <sys/utsname.h>
Lars-Peter Clausenb22da002016-04-21 14:58:53 +020038#include <time.h>
Romain Roffécead1da2015-06-30 13:35:51 +020039#include <unistd.h>
Romain Roffé6ce74a22015-06-30 11:45:11 +020040#include <fcntl.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010041
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020042#define DEFAULT_TIMEOUT_MS 1000
43
Paul Cercueil92f46df2014-04-28 13:17:53 +020044#define NB_BLOCKS 4
45
46#define BLOCK_ALLOC_IOCTL _IOWR('i', 0xa0, struct block_alloc_req)
47#define BLOCK_FREE_IOCTL _IO('i', 0xa1)
48#define BLOCK_QUERY_IOCTL _IOWR('i', 0xa2, struct block)
49#define BLOCK_ENQUEUE_IOCTL _IOWR('i', 0xa3, struct block)
50#define BLOCK_DEQUEUE_IOCTL _IOWR('i', 0xa4, struct block)
51
Paul Cercueil71694c72014-05-22 14:02:13 +020052#define BLOCK_FLAG_CYCLIC BIT(1)
53
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020054/* Forward declarations */
55static ssize_t local_read_dev_attr(const struct iio_device *dev,
56 const char *attr, char *dst, size_t len, bool is_debug);
57static ssize_t local_read_chn_attr(const struct iio_channel *chn,
58 const char *attr, char *dst, size_t len);
Paul Cercueil1da28122014-05-22 10:59:49 +020059static ssize_t local_write_dev_attr(const struct iio_device *dev,
60 const char *attr, const char *src, size_t len, bool is_debug);
61static ssize_t local_write_chn_attr(const struct iio_channel *chn,
62 const char *attr, const char *src, size_t len);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020063
Paul Cercueil92f46df2014-04-28 13:17:53 +020064struct block_alloc_req {
65 uint32_t type,
66 size,
67 count,
68 id;
69};
70
71struct block {
72 uint32_t id,
73 size,
74 bytes_used,
75 type,
76 flags,
77 offset;
78 uint64_t timestamp;
79};
80
Paul Cercueil00558f12016-04-12 14:40:40 +020081struct iio_context_pdata {
Lars-Peter Clausen8068be32016-04-22 10:36:34 +020082 unsigned int rw_timeout_ms;
Paul Cercueil00558f12016-04-12 14:40:40 +020083};
84
Paul Cercueileaab6582014-02-21 09:35:59 +010085struct iio_device_pdata {
Romain Roffé6ce74a22015-06-30 11:45:11 +020086 int fd;
Romain Roffécead1da2015-06-30 13:35:51 +020087 bool blocking;
Paul Cercueil71694c72014-05-22 14:02:13 +020088 unsigned int samples_count, nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +020089
Romain Roffé0f737472015-06-30 16:45:54 +020090 struct block *blocks;
91 void **addrs;
Paul Cercueil92f46df2014-04-28 13:17:53 +020092 int last_dequeued;
Paul Cercueil6ea8a752014-06-03 11:35:35 +020093 bool is_high_speed, cyclic, cyclic_buffer_enqueued, buffer_enabled;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +020094
95 int cancel_fd;
Paul Cercueileaab6582014-02-21 09:35:59 +010096};
97
Paul Cercueil3f9dcb02016-08-09 17:16:25 +020098struct iio_channel_pdata {
Paul Cercueila1a34c62016-08-09 12:53:39 +020099 char *enable_fn;
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200100};
101
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100102static const char * const device_attrs_blacklist[] = {
103 "dev",
104 "uevent",
105};
106
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200107static int ioctl_nointr(int fd, unsigned long request, void *data)
108{
109 int ret;
110
111 do {
112 ret = ioctl(fd, request, data);
113 } while (ret == -1 && errno == EINTR);
114
115 return ret;
116}
117
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200118static void local_free_channel_pdata(struct iio_channel *chn)
119{
Paul Cercueila1a34c62016-08-09 12:53:39 +0200120 if (chn->pdata) {
121 free(chn->pdata->enable_fn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200122 free(chn->pdata);
Paul Cercueila1a34c62016-08-09 12:53:39 +0200123 }
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200124}
125
Romain Roffé0f737472015-06-30 16:45:54 +0200126static void local_free_pdata(struct iio_device *device)
127{
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200128 unsigned int i;
129
130 for (i = 0; i < device->nb_channels; i++)
131 local_free_channel_pdata(device->channels[i]);
132
133 if (device->pdata) {
Romain Roffé0f737472015-06-30 16:45:54 +0200134 free(device->pdata->blocks);
135 free(device->pdata->addrs);
136 free(device->pdata);
137 }
138}
139
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100140static void local_shutdown(struct iio_context *ctx)
141{
Paul Cercueil42d12352014-05-05 16:11:58 +0200142 /* Free the backend data stored in every device structure */
Paul Cercueil167d3112014-02-18 12:23:53 +0100143 unsigned int i;
Paul Cercueil00558f12016-04-12 14:40:40 +0200144
Paul Cercueilb04d4d12016-08-01 15:46:06 +0200145 for (i = 0; i < ctx->nb_devices; i++) {
146 struct iio_device *dev = ctx->devices[i];
147
148 iio_device_close(dev);
149 local_free_pdata(dev);
150 }
Paul Cercueil00558f12016-04-12 14:40:40 +0200151
152 free(ctx->pdata);
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
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200215/*
216 * Used to generate the timeout parameter for operations like poll. Returns the
217 * number of ms until it is timeout_rel ms after the time specified in start. If
218 * timeout_rel is 0 returns -1 to indicate no timeout.
219 *
220 * The timeout that is specified for IIO operations is the maximum time a buffer
221 * push() or refill() operation should take before returning. poll() is used to
222 * wait for either data activity or for the timeout to elapse. poll() might get
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200223 * interrupted in which case it is called again or the read()/write() operation
224 * might not complete the full buffer size in one call in which case we go back
225 * to poll() again as well. Passing the same timeout as before would increase
226 * the total timeout and if repeated interruptions occur (e.g. by a timer
227 * signal) the operation might never time out or with significant delay. Hence
228 * before each poll() invocation the timeout is recalculated relative to the
229 * start of refill() or push() operation.
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200230 */
231static int get_rel_timeout_ms(struct timespec *start, unsigned int timeout_rel)
232{
233 struct timespec now;
234 int diff_ms;
235
236 if (timeout_rel == 0) /* No timeout */
237 return -1;
238
239 clock_gettime(CLOCK_MONOTONIC, &now);
240
241 diff_ms = (now.tv_sec - start->tv_sec) * 1000;
242 diff_ms += (now.tv_nsec - start->tv_nsec) / 1000000;
243
244 if (diff_ms >= timeout_rel) /* Expired */
245 return 0;
246 if (diff_ms > 0) /* Should never be false, but lets be safe */
247 timeout_rel -= diff_ms;
248 if (timeout_rel > INT_MAX)
249 return INT_MAX;
250
251 return (int) timeout_rel;
252}
253
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200254static int device_check_ready(const struct iio_device *dev, short events,
255 struct timespec *start)
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200256{
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200257 struct pollfd pollfd[2] = {
258 {
259 .fd = dev->pdata->fd,
260 .events = events,
261 }, {
262 .fd = dev->pdata->cancel_fd,
263 .events = POLLIN,
264 }
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200265 };
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200266 unsigned int rw_timeout_ms = dev->ctx->pdata->rw_timeout_ms;
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200267 int timeout_rel;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200268 int ret;
269
Romain Roffécead1da2015-06-30 13:35:51 +0200270 if (!dev->pdata->blocking)
271 return 0;
272
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200273 do {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200274 timeout_rel = get_rel_timeout_ms(start, rw_timeout_ms);
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200275 ret = poll(pollfd, 2, timeout_rel);
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200276 } while (ret == -1 && errno == EINTR);
277
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200278 if ((pollfd[1].revents & POLLIN))
279 return -EBADF;
280
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200281 if (ret < 0)
282 return -errno;
283 if (!ret)
284 return -ETIMEDOUT;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200285 if (pollfd[0].revents & POLLNVAL)
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200286 return -EBADF;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200287 if (!(pollfd[0].revents & events))
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200288 return -EIO;
289 return 0;
290}
291
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200292static ssize_t local_read(const struct iio_device *dev,
293 void *dst, size_t len, uint32_t *mask, size_t words)
Romain Roffé6ce74a22015-06-30 11:45:11 +0200294{
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200295 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200296 uintptr_t ptr = (uintptr_t) dst;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200297 struct timespec start;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200298 ssize_t readsize;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200299 ssize_t ret;
300
301 if (pdata->fd == -1)
302 return -EBADF;
303 if (words != dev->words)
304 return -EINVAL;
305
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200306 memcpy(mask, dev->mask, words);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200307
Lars-Peter Clausen8ba0d5b2016-02-17 11:30:23 +0100308 if (len == 0)
309 return 0;
310
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200311 clock_gettime(CLOCK_MONOTONIC, &start);
Lars-Peter Clausen525c93e2016-04-21 14:05:27 +0200312
Romain Roffé6ce74a22015-06-30 11:45:11 +0200313 while (len > 0) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200314 ret = device_check_ready(dev, POLLIN, &start);
315 if (ret < 0)
316 break;
317
Romain Roffé6ce74a22015-06-30 11:45:11 +0200318 do {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200319 ret = read(pdata->fd, (void *) ptr, len);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200320 } while (ret == -1 && errno == EINTR);
321
322 if (ret == -1) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200323 if (pdata->blocking && errno == EAGAIN)
324 continue;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200325 ret = -EIO;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200326 break;
327 } else if (ret == 0) {
328 ret = -EIO;
329 break;
330 }
331
332 ptr += ret;
333 len -= ret;
334 }
335
336 readsize = (ssize_t)(ptr - (uintptr_t) dst);
Romain Roffécead1da2015-06-30 13:35:51 +0200337 if ((ret > 0 || ret == -EAGAIN) && (readsize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200338 return readsize;
339 else
340 return ret;
341}
342
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200343static ssize_t local_write(const struct iio_device *dev,
344 const void *src, size_t len)
Romain Roffé6ce74a22015-06-30 11:45:11 +0200345{
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200346 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200347 uintptr_t ptr = (uintptr_t) src;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200348 struct timespec start;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200349 ssize_t writtensize;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200350 ssize_t ret;
351
352 if (pdata->fd == -1)
353 return -EBADF;
354
Lars-Peter Clausen525c93e2016-04-21 14:05:27 +0200355 if (len == 0)
356 return 0;
357
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200358 clock_gettime(CLOCK_MONOTONIC, &start);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200359
360 while (len > 0) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200361 ret = device_check_ready(dev, POLLOUT, &start);
362 if (ret < 0)
363 break;
364
Romain Roffé6ce74a22015-06-30 11:45:11 +0200365 do {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200366 ret = write(pdata->fd, (void *) ptr, len);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200367 } while (ret == -1 && errno == EINTR);
368
369 if (ret == -1) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200370 if (pdata->blocking && errno == EAGAIN)
371 continue;
372
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200373 ret = -EIO;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200374 break;
375 } else if (ret == 0) {
376 ret = -EIO;
377 break;
378 }
379
380 ptr += ret;
381 len -= ret;
382 }
383
384 writtensize = (ssize_t)(ptr - (uintptr_t) src);
Romain Roffécead1da2015-06-30 13:35:51 +0200385 if ((ret > 0 || ret == -EAGAIN) && (writtensize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200386 return writtensize;
387 else
388 return ret;
389}
390
Romain Roffécead1da2015-06-30 13:35:51 +0200391static ssize_t local_enable_buffer(const struct iio_device *dev)
392{
393 struct iio_device_pdata *pdata = dev->pdata;
394 ssize_t ret = 0;
395
396 if (!pdata->buffer_enabled) {
397 ret = local_write_dev_attr(dev,
398 "buffer/enable", "1", 2, false);
399 if (ret >= 0)
400 pdata->buffer_enabled = true;
401 }
402
403 return 0;
404}
Romain Roffé6ce74a22015-06-30 11:45:11 +0200405
Romain Roffé0f737472015-06-30 16:45:54 +0200406static int local_set_kernel_buffers_count(const struct iio_device *dev,
407 unsigned int nb_blocks)
408{
409 struct iio_device_pdata *pdata = dev->pdata;
410
411 if (pdata->fd != -1)
412 return -EBUSY;
413
414 pdata->nb_blocks = nb_blocks;
415
416 return 0;
417}
418
Paul Cercueil92f46df2014-04-28 13:17:53 +0200419static ssize_t local_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100420 void **addr_ptr, size_t bytes_used,
421 uint32_t *mask, size_t words)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200422{
423 struct block block;
424 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200425 struct timespec start;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200426 char err_str[1024];
Romain Roffé6ce74a22015-06-30 11:45:11 +0200427 int f = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200428 ssize_t ret;
429
430 if (!pdata->is_high_speed)
431 return -ENOSYS;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200432 if (f == -1)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200433 return -EBADF;
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200434 if (!addr_ptr)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200435 return -EINVAL;
436
Paul Cercueil92f46df2014-04-28 13:17:53 +0200437 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200438 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200439
440 if (pdata->cyclic) {
441 if (pdata->cyclic_buffer_enqueued)
442 return -EBUSY;
443 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
444 pdata->cyclic_buffer_enqueued = true;
445 }
446
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200447 last_block->bytes_used = bytes_used;
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200448 ret = (ssize_t) ioctl_nointr(f,
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200449 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200450 if (ret) {
451 ret = (ssize_t) -errno;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200452 iio_strerror(errno, err_str, sizeof(err_str));
453 ERROR("Unable to enqueue block: %s\n", err_str);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200454 return ret;
455 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200456
457 if (pdata->cyclic) {
458 *addr_ptr = pdata->addrs[pdata->last_dequeued];
459 return (ssize_t) last_block->bytes_used;
460 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200461 }
462
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200463 clock_gettime(CLOCK_MONOTONIC, &start);
Lars-Peter Clausene63811e2016-04-21 11:22:33 +0200464
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200465 do {
466 ret = (ssize_t) device_check_ready(dev, POLLIN | POLLOUT, &start);
467 if (ret < 0)
468 return ret;
469
470 memset(&block, 0, sizeof(block));
471 ret = (ssize_t) ioctl_nointr(f, BLOCK_DEQUEUE_IOCTL, &block);
472 } while (pdata->blocking && ret == -1 && errno == EAGAIN);
473
Paul Cercueil92f46df2014-04-28 13:17:53 +0200474 if (ret) {
475 ret = (ssize_t) -errno;
Paul Cercueilea51a3f2016-05-25 17:22:03 +0200476 if ((!pdata->blocking && ret != -EAGAIN) ||
477 (pdata->blocking && ret != -ETIMEDOUT)) {
Lars-Peter Clausenf8408352016-04-25 10:43:11 +0200478 iio_strerror(errno, err_str, sizeof(err_str));
479 ERROR("Unable to dequeue block: %s\n", err_str);
480 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200481 return ret;
482 }
483
Paul Cercueil558ade42014-11-27 10:59:48 +0100484 /* Requested buffer size is too big! */
485 if (pdata->last_dequeued < 0 && bytes_used != block.size)
486 return -EFBIG;
487
Paul Cercueil92f46df2014-04-28 13:17:53 +0200488 pdata->last_dequeued = block.id;
489 *addr_ptr = pdata->addrs[block.id];
490 return (ssize_t) block.bytes_used;
491}
492
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200493static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
494 char *dst, size_t len, bool is_debug)
495{
496 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
497 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
498 char *ptr = dst;
499
500 for (i = 0; len >= 4 && i < nb; i++) {
501 /* Recursive! */
502 ssize_t ret = local_read_dev_attr(dev, attrs[i],
503 ptr + 4, len - 4, is_debug);
Paul Cercueil2042c902016-04-25 18:43:45 +0200504 *(uint32_t *) ptr = iio_htobe32(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200505
506 /* Align the length to 4 bytes */
507 if (ret > 0 && ret & 3)
508 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200509 ptr += 4 + (ret < 0 ? 0 : ret);
510 len -= 4 + (ret < 0 ? 0 : ret);
511 }
512
513 return ptr - dst;
514}
515
516static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
517 char *dst, size_t len)
518{
519 unsigned int i;
520 char *ptr = dst;
521
522 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
523 /* Recursive! */
524 ssize_t ret = local_read_chn_attr(chn,
525 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil2042c902016-04-25 18:43:45 +0200526 *(uint32_t *) ptr = iio_htobe32(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200527
528 /* Align the length to 4 bytes */
529 if (ret > 0 && ret & 3)
530 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200531 ptr += 4 + (ret < 0 ? 0 : ret);
532 len -= 4 + (ret < 0 ? 0 : ret);
533 }
534
535 return ptr - dst;
536}
537
Paul Cercueil1da28122014-05-22 10:59:49 +0200538static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
539{
540 while (nb--) {
541 int32_t val;
542
543 if (len < 4)
544 return -EINVAL;
545
Paul Cercueil2042c902016-04-25 18:43:45 +0200546 val = (int32_t) iio_be32toh(*(uint32_t *) src);
Paul Cercueil1da28122014-05-22 10:59:49 +0200547 src += 4;
548 len -= 4;
549
550 if (val > 0) {
551 if ((uint32_t) val > len)
552 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200553
554 /* Align the length to 4 bytes */
555 if (val & 3)
556 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200557 len -= val;
558 src += val;
559 }
560 }
561
562 /* We should have analyzed the whole buffer by now */
563 return !len ? 0 : -EINVAL;
564}
565
566static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
567 const char *src, size_t len, bool is_debug)
568{
569 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
570 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
571 const char *ptr = src;
572
573 /* First step: Verify that the buffer is in the correct format */
574 if (local_buffer_analyze(nb, src, len))
575 return -EINVAL;
576
577 /* Second step: write the attributes */
578 for (i = 0; i < nb; i++) {
Paul Cercueil2042c902016-04-25 18:43:45 +0200579 int32_t val = (int32_t) iio_be32toh(*(uint32_t *) ptr);
Paul Cercueil1da28122014-05-22 10:59:49 +0200580 ptr += 4;
581
582 if (val > 0) {
583 local_write_dev_attr(dev, attrs[i], ptr, val, is_debug);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200584
585 /* Align the length to 4 bytes */
586 if (val & 3)
587 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200588 ptr += val;
589 }
590 }
591
592 return ptr - src;
593}
594
595static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
596 const char *src, size_t len)
597{
598 unsigned int i, nb = chn->nb_attrs;
599 const char *ptr = src;
600
601 /* First step: Verify that the buffer is in the correct format */
602 if (local_buffer_analyze(nb, src, len))
603 return -EINVAL;
604
605 /* Second step: write the attributes */
606 for (i = 0; i < nb; i++) {
Paul Cercueil2042c902016-04-25 18:43:45 +0200607 int32_t val = (int32_t) iio_be32toh(*(uint32_t *) ptr);
Paul Cercueil1da28122014-05-22 10:59:49 +0200608 ptr += 4;
609
610 if (val > 0) {
611 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200612
613 /* Align the length to 4 bytes */
614 if (val & 3)
615 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200616 ptr += val;
617 }
618 }
619
620 return ptr - src;
621}
622
Paul Cercueil167d3112014-02-18 12:23:53 +0100623static ssize_t local_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200624 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100625{
Paul Cercueil3e898302014-02-17 16:17:11 +0100626 FILE *f;
627 char buf[1024];
628 ssize_t ret;
629
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200630 if (!attr)
631 return local_read_all_dev_attrs(dev, dst, len, is_debug);
632
Paul Cercueil50c762a2014-04-14 15:55:43 +0200633 if (is_debug)
634 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
635 dev->id, attr);
636 else
637 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
638 dev->id, attr);
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100639 f = fopen(buf, "re");
Paul Cercueil3e898302014-02-17 16:17:11 +0100640 if (!f)
641 return -errno;
642
643 ret = fread(dst, 1, len, f);
644 if (ret > 0)
645 dst[ret - 1] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100646 fflush(f);
647 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200648 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100649 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200650 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100651}
652
Paul Cercueil167d3112014-02-18 12:23:53 +0100653static ssize_t local_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200654 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100655{
Paul Cercueil3e898302014-02-17 16:17:11 +0100656 FILE *f;
657 char buf[1024];
658 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100659
Paul Cercueil1da28122014-05-22 10:59:49 +0200660 if (!attr)
661 return local_write_all_dev_attrs(dev, src, len, is_debug);
662
Paul Cercueil50c762a2014-04-14 15:55:43 +0200663 if (is_debug)
664 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
665 dev->id, attr);
666 else
667 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
668 dev->id, attr);
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100669 f = fopen(buf, "we");
Paul Cercueil3e898302014-02-17 16:17:11 +0100670 if (!f)
671 return -errno;
672
673 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100674 fflush(f);
675 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200676 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100677 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200678 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100679}
680
Paul Cercueil167d3112014-02-18 12:23:53 +0100681static const char * get_filename(const struct iio_channel *chn,
682 const char *attr)
683{
Paul Cercueil167d3112014-02-18 12:23:53 +0100684 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200685 for (i = 0; i < chn->nb_attrs; i++)
686 if (!strcmp(attr, chn->attrs[i].name))
687 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100688 return attr;
689}
690
691static ssize_t local_read_chn_attr(const struct iio_channel *chn,
692 const char *attr, char *dst, size_t len)
693{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200694 if (!attr)
695 return local_read_all_chn_attrs(chn, dst, len);
696
Paul Cercueil167d3112014-02-18 12:23:53 +0100697 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200698 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100699}
700
701static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200702 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100703{
Paul Cercueil1da28122014-05-22 10:59:49 +0200704 if (!attr)
705 return local_write_all_chn_attrs(chn, src, len);
706
Paul Cercueil167d3112014-02-18 12:23:53 +0100707 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200708 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100709}
710
Paul Cercueilff778232014-03-24 14:23:08 +0100711static int channel_write_state(const struct iio_channel *chn)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100712{
Paul Cercueilff778232014-03-24 14:23:08 +0100713 char *en = iio_channel_is_enabled(chn) ? "1" : "0";
Paul Cercueila1a34c62016-08-09 12:53:39 +0200714 ssize_t ret;
715
716 if (!chn->pdata || !chn->pdata->enable_fn) {
717 ERROR("Libiio bug: No \"en\" attribute parsed\n");
718 return -EINVAL;
719 }
720
721 ret = local_write_chn_attr(chn, chn->pdata->enable_fn, en, 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100722 if (ret < 0)
723 return (int) ret;
724 else
725 return 0;
726}
727
Paul Cercueil92f46df2014-04-28 13:17:53 +0200728static int enable_high_speed(const struct iio_device *dev)
729{
730 struct block_alloc_req req;
731 struct iio_device_pdata *pdata = dev->pdata;
732 unsigned int i;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200733 int ret, fd = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200734
Paul Cercueil71694c72014-05-22 14:02:13 +0200735 if (pdata->cyclic) {
736 pdata->nb_blocks = 1;
737 DEBUG("Enabling cyclic mode\n");
738 } else {
Paul Cercueil71694c72014-05-22 14:02:13 +0200739 DEBUG("Cyclic mode not enabled\n");
740 }
741
Romain Roffé0f737472015-06-30 16:45:54 +0200742 pdata->blocks = calloc(pdata->nb_blocks, sizeof(*pdata->blocks));
743 if (!pdata->blocks) {
744 pdata->nb_blocks = 0;
745 return -ENOMEM;
746 }
747
748 pdata->addrs = calloc(pdata->nb_blocks, sizeof(*pdata->addrs));
749 if (!pdata->addrs) {
750 free(pdata->blocks);
751 pdata->blocks = NULL;
752 return -ENOMEM;
753 }
754
Paul Cercueil1fa913d2015-04-28 16:30:53 +0200755 req.id = 0;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200756 req.type = 0;
757 req.size = pdata->samples_count *
758 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Paul Cercueil71694c72014-05-22 14:02:13 +0200759 req.count = pdata->nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200760
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200761 ret = ioctl_nointr(fd, BLOCK_ALLOC_IOCTL, &req);
Romain Roffé0f737472015-06-30 16:45:54 +0200762 if (ret < 0) {
763 ret = -errno;
764 goto err_freemem;
765 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200766
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200767 /* We might get less blocks than what we asked for */
768 pdata->nb_blocks = req.count;
769
Paul Cercueil92f46df2014-04-28 13:17:53 +0200770 /* mmap all the blocks */
Paul Cercueil71694c72014-05-22 14:02:13 +0200771 for (i = 0; i < pdata->nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200772 pdata->blocks[i].id = i;
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200773 ret = ioctl_nointr(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200774 if (ret) {
775 ret = -errno;
776 goto err_munmap;
777 }
778
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200779 ret = ioctl_nointr(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200780 if (ret) {
781 ret = -errno;
782 goto err_munmap;
783 }
784
Paul Cercueil032a5652014-05-12 17:11:19 +0200785 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
786 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200787 MAP_SHARED, fd, pdata->blocks[i].offset);
788 if (pdata->addrs[i] == MAP_FAILED) {
789 ret = -errno;
790 goto err_munmap;
791 }
792 }
793
Paul Cercueil4a702d32014-05-12 17:02:37 +0200794 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200795 return 0;
796
797err_munmap:
798 for (; i > 0; i--)
799 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200800 ioctl_nointr(fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200801err_freemem:
802 free(pdata->addrs);
803 pdata->addrs = NULL;
804 free(pdata->blocks);
805 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200806 return ret;
807}
808
Paul Cercueil92f15c22015-04-20 11:36:51 +0200809static int local_open(const struct iio_device *dev,
810 size_t samples_count, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100811{
812 unsigned int i;
813 int ret;
814 char buf[1024];
815 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200816
Romain Roffé6ce74a22015-06-30 11:45:11 +0200817 if (pdata->fd != -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100818 return -EBUSY;
819
Paul Cercueilcecda352014-05-06 18:14:29 +0200820 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200821 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100822 return ret;
823
Paul Cercueil11334342015-06-23 16:55:35 +0200824 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200825 ret = local_write_dev_attr(dev, "buffer/length",
826 buf, strlen(buf) + 1, false);
827 if (ret < 0)
828 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200829
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200830 pdata->cancel_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
831 if (pdata->cancel_fd == -1)
832 return -errno;
833
Paul Cercueil8c29e412014-04-07 09:46:45 +0200834 snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200835 pdata->fd = open(buf, O_RDWR | O_CLOEXEC | O_NONBLOCK);
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200836 if (pdata->fd == -1) {
837 ret = -errno;
838 goto err_close_cancel_fd;
839 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100840
Paul Cercueil11334342015-06-23 16:55:35 +0200841 /* Disable channels */
842 for (i = 0; i < dev->nb_channels; i++) {
843 struct iio_channel *chn = dev->channels[i];
844 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
845 ret = channel_write_state(chn);
846 if (ret < 0)
847 goto err_close;
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100848 }
Paul Cercueil11334342015-06-23 16:55:35 +0200849 }
850 /* Enable channels */
851 for (i = 0; i < dev->nb_channels; i++) {
852 struct iio_channel *chn = dev->channels[i];
853 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
854 ret = channel_write_state(chn);
855 if (ret < 0)
856 goto err_close;
Paul Cercueile1311222014-03-12 15:46:16 +0100857 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100858 }
859
Paul Cercueil71694c72014-05-22 14:02:13 +0200860 pdata->cyclic = cyclic;
861 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200862 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200863 pdata->samples_count = samples_count;
Paul Cercueil71694c72014-05-22 14:02:13 +0200864 pdata->is_high_speed = !enable_high_speed(dev);
Paul Cercueilb762fc62014-05-12 16:56:09 +0200865
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200866 if (!pdata->is_high_speed) {
Romain Roffé0f737472015-06-30 16:45:54 +0200867 unsigned long size = samples_count * pdata->nb_blocks;
Paul Cercueil032a5652014-05-12 17:11:19 +0200868 WARNING("High-speed mode not enabled\n");
Paul Cercueiled621ee2015-06-24 10:50:21 +0200869
Lars-Peter Clausen23804792016-04-20 18:17:56 +0200870 /* Cyclic mode is only supported in high-speed mode */
Lars-Peter Clausen3e8774c2016-09-21 16:49:32 +0200871 if (cyclic) {
872 ret = -EPERM;
873 goto err_close;
874 }
Lars-Peter Clausen23804792016-04-20 18:17:56 +0200875
Paul Cercueiled621ee2015-06-24 10:50:21 +0200876 /* Increase the size of the kernel buffer, when using the
877 * low-speed interface. This avoids losing samples when
878 * refilling the iio_buffer. */
Romain Roffé0f737472015-06-30 16:45:54 +0200879 snprintf(buf, sizeof(buf), "%lu", size);
Paul Cercueiled621ee2015-06-24 10:50:21 +0200880 ret = local_write_dev_attr(dev, "buffer/length",
881 buf, strlen(buf) + 1, false);
882 if (ret < 0)
883 goto err_close;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200884 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100885
Lars-Peter Clausen53d6d452016-04-20 17:46:11 +0200886 ret = local_enable_buffer(dev);
887 if (ret < 0)
888 goto err_close;
889
Paul Cercueil45c575d2014-03-20 15:14:01 +0100890 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +0100891err_close:
Romain Roffé6ce74a22015-06-30 11:45:11 +0200892 close(pdata->fd);
893 pdata->fd = -1;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200894err_close_cancel_fd:
895 close(pdata->cancel_fd);
896 pdata->cancel_fd = -1;
Paul Cercueile1311222014-03-12 15:46:16 +0100897 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100898}
899
900static int local_close(const struct iio_device *dev)
901{
902 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100903 int ret;
904
Paul Cercueilb6a40c22015-07-02 11:12:16 +0200905 if (pdata->fd == -1)
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100906 return -EBADF;
907
Paul Cercueil92f46df2014-04-28 13:17:53 +0200908 if (pdata->is_high_speed) {
909 unsigned int i;
Paul Cercueil71694c72014-05-22 14:02:13 +0200910 for (i = 0; i < pdata->nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200911 munmap(pdata->addrs[i], pdata->blocks[i].size);
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200912 ioctl_nointr(pdata->fd, BLOCK_FREE_IOCTL, 0);
Romain Roffé0f737472015-06-30 16:45:54 +0200913 free(pdata->addrs);
914 pdata->addrs = NULL;
915 free(pdata->blocks);
916 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200917 }
918
Romain Roffé6ce74a22015-06-30 11:45:11 +0200919 ret = close(pdata->fd);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100920 if (ret)
921 return ret;
922
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200923 close(pdata->cancel_fd);
924
Romain Roffé6ce74a22015-06-30 11:45:11 +0200925 pdata->fd = -1;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200926 pdata->cancel_fd = -1;
927
Paul Cercueil71694c72014-05-22 14:02:13 +0200928 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
929 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100930}
931
Romain Roffé87897862015-06-30 13:34:08 +0200932static int local_get_fd(const struct iio_device *dev)
933{
Paul Cercueil2cdc81b2015-07-02 11:13:23 +0200934 if (dev->pdata->fd == -1)
935 return -EBADF;
936 else
937 return dev->pdata->fd;
Romain Roffé87897862015-06-30 13:34:08 +0200938}
939
Romain Roffécead1da2015-06-30 13:35:51 +0200940static int local_set_blocking_mode(const struct iio_device *dev, bool blocking)
941{
Romain Roffécead1da2015-06-30 13:35:51 +0200942 if (dev->pdata->fd == -1)
943 return -EBADF;
944
945 if (dev->pdata->cyclic)
946 return -EPERM;
947
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200948 dev->pdata->blocking = blocking;
Romain Roffécead1da2015-06-30 13:35:51 +0200949
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200950 return 0;
Romain Roffécead1da2015-06-30 13:35:51 +0200951}
952
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100953static int local_get_trigger(const struct iio_device *dev,
954 const struct iio_device **trigger)
955{
956 char buf[1024];
957 unsigned int i;
958 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +0200959 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +0200960 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100961 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100962 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +0200963 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100964
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200965 if (buf[0] == '\0') {
966 *trigger = NULL;
967 return 0;
968 }
969
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100970 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +0200971 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100972 const struct iio_device *cur = dev->ctx->devices[i];
973 if (cur->name && !strcmp(cur->name, buf)) {
974 *trigger = cur;
975 return 0;
976 }
977 }
978 return -ENXIO;
979}
980
981static int local_set_trigger(const struct iio_device *dev,
982 const struct iio_device *trigger)
983{
984 ssize_t nb;
985 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +0200986 nb = local_write_dev_attr(dev, "trigger/current_trigger",
987 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100988 if (nb < 0)
989 return (int) nb;
990 else
991 return 0;
992}
993
Lars-Peter Clausend9806c22016-01-26 16:35:42 +0100994static bool is_channel(const char *attr, bool strict)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100995{
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100996 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +0100997 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
998 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100999 if (!strncmp(attr, "in_", 3))
1000 ptr = strchr(attr + 3, '_');
1001 else if (!strncmp(attr, "out_", 4))
1002 ptr = strchr(attr + 4, '_');
1003 if (!ptr)
1004 return false;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001005 if (!strict)
1006 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001007 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
1008 return true;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001009
Lars-Peter Clausen093ae462016-06-21 11:43:54 +02001010 if (find_channel_modifier(ptr + 1, NULL) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001011 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001012 return false;
1013}
1014
1015static char * get_channel_id(const char *attr)
1016{
1017 char *res, *ptr;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001018 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001019
1020 attr = strchr(attr, '_') + 1;
1021 ptr = strchr(attr, '_');
Lars-Peter Clausen093ae462016-06-21 11:43:54 +02001022 if (find_channel_modifier(ptr + 1, &len) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001023 ptr += len + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001024
1025 res = malloc(ptr - attr + 1);
1026 if (!res)
1027 return NULL;
1028
1029 memcpy(res, attr, ptr - attr);
1030 res[ptr - attr] = 0;
1031 return res;
1032}
1033
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001034static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001035{
1036 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001037 size_t len;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +02001038
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001039 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausen093ae462016-06-21 11:43:54 +02001040 if (find_channel_modifier(ptr, &len) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001041 ptr += len + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +02001042
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001043 if (chn->name) {
1044 size_t len = strlen(chn->name);
1045 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
1046 ptr += len + 1;
1047 }
1048
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001049 return iio_strdup(ptr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001050}
1051
1052static int read_device_name(struct iio_device *dev)
1053{
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001054 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +02001055 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +01001056 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001057 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +01001058 else if (ret == 0)
1059 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001060
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001061 dev->name = iio_strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001062 if (!dev->name)
1063 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +01001064 else
1065 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001066}
1067
1068static int add_attr_to_device(struct iio_device *dev, const char *attr)
1069{
Paul Cercueilbb618272014-02-20 11:35:52 +01001070 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001071 unsigned int i;
1072
1073 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
1074 if (!strcmp(device_attrs_blacklist[i], attr))
1075 return 0;
1076
1077 if (!strcmp(attr, "name"))
1078 return read_device_name(dev);
1079
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001080 name = iio_strdup(attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001081 if (!name)
1082 return -ENOMEM;
1083
1084 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
1085 if (!attrs) {
1086 free(name);
1087 return -ENOMEM;
1088 }
1089
1090 attrs[dev->nb_attrs++] = name;
1091 dev->attrs = attrs;
1092 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
1093 return 0;
1094}
1095
Paul Cercueila1a34c62016-08-09 12:53:39 +02001096static int handle_protected_scan_element_attr(struct iio_channel *chn,
1097 const char *name, const char *path)
1098{
1099 struct iio_device *dev = chn->dev;
1100 char buf[1024];
1101 int ret;
1102
1103 if (!strcmp(name, "index")) {
1104 ret = local_read_dev_attr(dev, path, buf, sizeof(buf), false);
1105 if (ret > 0)
1106 chn->index = atol(buf);
1107
1108 } else if (!strcmp(name, "type")) {
1109 ret = local_read_dev_attr(dev, path, buf, sizeof(buf), false);
1110 if (ret > 0) {
1111 char endian, sign;
1112
Lucas Magasweran77fe2912016-08-29 13:47:29 -07001113 if (strchr(buf, 'X')) {
1114 sscanf(buf, "%ce:%c%u/%uX%u>>%u", &endian, &sign,
1115 &chn->format.bits, &chn->format.length,
1116 &chn->format.repeat, &chn->format.shift);
1117 } else {
1118 chn->format.repeat = 1;
1119 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001120 &chn->format.bits, &chn->format.length,
1121 &chn->format.shift);
Lucas Magasweran77fe2912016-08-29 13:47:29 -07001122 }
Paul Cercueila1a34c62016-08-09 12:53:39 +02001123 chn->format.is_signed = (sign == 's' || sign == 'S');
1124 chn->format.is_fully_defined =
1125 (sign == 'S' || sign == 'U'||
1126 chn->format.bits == chn->format.length);
1127 chn->format.is_be = endian == 'b';
1128 }
1129
1130 } else if (!strcmp(name, "en")) {
1131 if (chn->pdata->enable_fn) {
1132 ERROR("Libiio bug: \"en\" attribute already parsed for channel %s!\n",
1133 chn->id);
1134 return -EINVAL;
1135 }
1136
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001137 chn->pdata->enable_fn = iio_strdup(path);
Paul Cercueila1a34c62016-08-09 12:53:39 +02001138 if (!chn->pdata->enable_fn)
1139 return -ENOMEM;
1140
1141 } else {
1142 return -EINVAL;
1143 }
1144
1145 return 0;
1146}
1147
Paul Cercueile3fbd952014-03-11 16:58:33 +01001148static int add_attr_to_channel(struct iio_channel *chn,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001149 const char *attr, const char *path, bool is_scan_element)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001150{
Paul Cercueilb34e0222014-05-05 15:32:38 +02001151 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001152 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001153 if (!name)
1154 return -ENOMEM;
1155
Paul Cercueila1a34c62016-08-09 12:53:39 +02001156 if (is_scan_element) {
1157 int ret = handle_protected_scan_element_attr(chn, name, path);
1158
1159 free(name);
1160 return ret;
1161 }
1162
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001163 fn = iio_strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +01001164 if (!fn)
1165 goto err_free_name;
1166
Paul Cercueilb34e0222014-05-05 15:32:38 +02001167 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
1168 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +01001169 if (!attrs)
1170 goto err_free_fn;
1171
Paul Cercueil42d12352014-05-05 16:11:58 +02001172 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +02001173 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001174 chn->attrs = attrs;
1175 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
1176 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +01001177
Paul Cercueil167d3112014-02-18 12:23:53 +01001178err_free_fn:
1179 free(fn);
1180err_free_name:
1181 free(name);
1182 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001183}
1184
1185static int add_channel_to_device(struct iio_device *dev,
1186 struct iio_channel *chn)
1187{
1188 struct iio_channel **channels = realloc(dev->channels,
1189 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
1190 if (!channels)
1191 return -ENOMEM;
1192
1193 channels[dev->nb_channels++] = chn;
1194 dev->channels = channels;
1195 DEBUG("Added channel \'%s\' to device \'%s\'\n", chn->id, dev->id);
1196 return 0;
1197}
1198
1199static int add_device_to_context(struct iio_context *ctx,
1200 struct iio_device *dev)
1201{
1202 struct iio_device **devices = realloc(ctx->devices,
1203 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
1204 if (!devices)
1205 return -ENOMEM;
1206
1207 devices[ctx->nb_devices++] = dev;
1208 ctx->devices = devices;
1209 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
1210 return 0;
1211}
1212
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001213static struct iio_channel *create_channel(struct iio_device *dev,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001214 char *id, const char *attr, const char *path,
1215 bool is_scan_element)
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001216{
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001217 struct iio_channel *chn = zalloc(sizeof(*chn));
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001218 if (!chn)
1219 return NULL;
1220
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001221 chn->pdata = zalloc(sizeof(*chn->pdata));
1222 if (!chn->pdata)
1223 goto err_free_chn;
1224
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001225 if (!strncmp(attr, "out_", 4))
1226 chn->is_output = true;
1227 else if (strncmp(attr, "in_", 3))
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001228 goto err_free_chn_pdata;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001229
1230 chn->dev = dev;
1231 chn->id = id;
Paul Cercueila1a34c62016-08-09 12:53:39 +02001232 chn->is_scan_element = is_scan_element;
1233 chn->index = -ENOENT;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001234
Paul Cercueila1a34c62016-08-09 12:53:39 +02001235 if (!add_attr_to_channel(chn, attr, path, is_scan_element))
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001236 return chn;
1237
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001238err_free_chn_pdata:
1239 free(chn->pdata->enable_fn);
1240 free(chn->pdata);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001241err_free_chn:
1242 free(chn);
1243 return NULL;
1244}
1245
1246static int add_channel(struct iio_device *dev, const char *name,
1247 const char *path, bool dir_is_scan_elements)
1248{
1249 struct iio_channel *chn;
1250 char *channel_id;
1251 unsigned int i;
1252 int ret;
1253
1254 channel_id = get_channel_id(name);
1255 if (!channel_id)
1256 return -ENOMEM;
1257
1258 for (i = 0; i < dev->nb_channels; i++) {
1259 chn = dev->channels[i];
1260 if (!strcmp(chn->id, channel_id)
1261 && chn->is_output == (name[0] == 'o')) {
1262 free(channel_id);
Paul Cercueila1a34c62016-08-09 12:53:39 +02001263 ret = add_attr_to_channel(chn, name, path,
1264 dir_is_scan_elements);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001265 chn->is_scan_element = dir_is_scan_elements && !ret;
1266 return ret;
1267 }
1268 }
1269
Paul Cercueila1a34c62016-08-09 12:53:39 +02001270 chn = create_channel(dev, channel_id, name, path, dir_is_scan_elements);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001271 if (!chn) {
1272 free(channel_id);
1273 return -ENXIO;
1274 }
Lars-Peter Clausenc6f85922016-04-20 15:03:49 +02001275
1276 iio_channel_init_finalize(chn);
1277
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001278 ret = add_channel_to_device(dev, chn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001279 if (ret) {
1280 free(chn->pdata->enable_fn);
1281 free(chn->pdata);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001282 free_channel(chn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001283 }
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001284 return ret;
1285}
1286
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001287/*
1288 * Possible return values:
1289 * 0 = Attribute should not be moved to the channel
1290 * 1 = Attribute should be moved to the channel and it is a shared attribute
1291 * 2 = Attribute should be moved to the channel and it is a private attribute
1292 */
1293static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001294{
Lars-Peter Clausen8ba0d5b2016-02-17 11:30:23 +01001295 unsigned int len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001296 char *ptr;
1297
Paul Cercueil35a01312014-02-20 10:56:57 +01001298 if (!chn->is_output && !strncmp(attr, "in_", 3))
1299 attr += 3;
1300 else if (chn->is_output && !strncmp(attr, "out_", 4))
1301 attr += 4;
1302 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001303 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001304
1305 ptr = strchr(attr, '_');
1306 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001307 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001308
1309 len = ptr - attr;
1310
1311 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001312 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001313
1314 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001315 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1316 if (chn->name) {
1317 size_t name_len = strlen(chn->name);
1318 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1319 attr[len + 1 + name_len] == '_')
1320 return 2;
1321 }
1322 return 1;
1323 } else if (chn->id[len] != '_') {
1324 return 0;
1325 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001326
Lars-Peter Clausen093ae462016-06-21 11:43:54 +02001327 if (find_channel_modifier(chn->id + len + 1, NULL) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001328 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001329
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001330 return 0;
1331}
1332
1333static int detect_global_attr(struct iio_device *dev, const char *attr,
1334 unsigned int level, bool *match)
1335{
1336 unsigned int i;
1337
1338 *match = false;
1339 for (i = 0; i < dev->nb_channels; i++) {
1340 struct iio_channel *chn = dev->channels[i];
1341 if (is_global_attr(chn, attr) == level) {
1342 int ret;
1343 *match = true;
Paul Cercueila1a34c62016-08-09 12:53:39 +02001344 ret = add_attr_to_channel(chn, attr, attr, false);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001345 if (ret)
1346 return ret;
1347 }
1348 }
1349
1350 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001351}
1352
1353static int detect_and_move_global_attrs(struct iio_device *dev)
1354{
1355 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001356 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001357
1358 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001359 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001360 bool match;
1361 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001362
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001363 ret = detect_global_attr(dev, attr, 2, &match);
1364 if (ret)
1365 return ret;
1366
1367 if (!match) {
1368 ret = detect_global_attr(dev, attr, 1, &match);
1369 if (ret)
1370 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001371 }
1372
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001373 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001374 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001375 dev->attrs[i] = NULL;
1376 }
1377 }
1378
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001379 /* Find channels without an index */
1380 for (i = 0; i < dev->nb_attrs; i++) {
1381 const char *attr = dev->attrs[i];
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001382 int ret;
1383
1384 if (!dev->attrs[i])
1385 continue;
1386
1387 if (is_channel(attr, false)) {
1388 ret = add_channel(dev, attr, attr, false);
1389 if (ret)
1390 return ret;
1391
1392 free(dev->attrs[i]);
1393 dev->attrs[i] = NULL;
1394 }
1395 }
1396
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001397 for (i = 0; i < dev->nb_attrs; i++) {
1398 if (dev->attrs[i])
1399 *ptr++ = dev->attrs[i];
1400 }
1401
1402 dev->nb_attrs = ptr - dev->attrs;
Lars-Peter Clausene8a2bb32016-04-12 18:43:31 +02001403 if (!dev->nb_attrs) {
1404 free(dev->attrs);
1405 dev->attrs = NULL;
1406 }
1407
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001408 return 0;
1409}
1410
Paul Cercueile3fbd952014-03-11 16:58:33 +01001411static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001412 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001413{
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001414 char buf[1024];
Paul Cercueil1be57832014-03-11 16:27:16 +01001415 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001416
1417 if (dir_is_scan_elements) {
1418 snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001419 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001420 } else {
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001421 if (!is_channel(name, true))
1422 return add_attr_to_device(dev, name);
Paul Cercueila91358e2014-04-24 16:40:19 +02001423 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001424 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001425
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001426 return add_channel(dev, name, path, dir_is_scan_elements);
Paul Cercueil1be57832014-03-11 16:27:16 +01001427}
1428
Paul Cercueile3fbd952014-03-11 16:58:33 +01001429static int add_attr_or_channel(void *d, const char *path)
1430{
Paul Cercueila91358e2014-04-24 16:40:19 +02001431 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001432}
1433
1434static int add_scan_element(void *d, const char *path)
1435{
Paul Cercueila91358e2014-04-24 16:40:19 +02001436 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001437}
1438
Paul Cercueil1be57832014-03-11 16:27:16 +01001439static int foreach_in_dir(void *d, const char *path, bool is_dir,
1440 int (*callback)(void *, const char *))
1441{
Paul Cercueil883204f2016-11-17 12:35:28 +01001442 struct dirent *entry;
1443 DIR *dir;
1444 int ret = 0;
1445
1446 dir = opendir(path);
Paul Cercueil1be57832014-03-11 16:27:16 +01001447 if (!dir)
1448 return -errno;
1449
Paul Cercueil1be57832014-03-11 16:27:16 +01001450 while (true) {
1451 struct stat st;
1452 char buf[1024];
Paul Cercueil883204f2016-11-17 12:35:28 +01001453
1454 errno = 0;
1455 entry = readdir(dir);
1456 if (!entry) {
1457 if (!errno)
1458 break;
1459
1460 ret = -errno;
1461 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001462 ERROR("Unable to open directory %s: %s\n", path, buf);
Paul Cercueil883204f2016-11-17 12:35:28 +01001463 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001464 }
Paul Cercueil1be57832014-03-11 16:27:16 +01001465
1466 snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
1467 if (stat(buf, &st) < 0) {
1468 ret = -errno;
Paul Cercueil87b988f2015-05-22 10:57:32 +02001469 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001470 ERROR("Unable to stat file: %s\n", buf);
Paul Cercueil883204f2016-11-17 12:35:28 +01001471 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001472 }
1473
1474 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1475 ret = callback(d, buf);
1476 else if (!is_dir && S_ISREG(st.st_mode))
1477 ret = callback(d, buf);
1478 else
1479 continue;
1480
Paul Cercueil883204f2016-11-17 12:35:28 +01001481 if (ret < 0)
1482 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001483 }
1484
Paul Cercueil883204f2016-11-17 12:35:28 +01001485out_close_dir:
Paul Cercueil1be57832014-03-11 16:27:16 +01001486 closedir(dir);
Paul Cercueil883204f2016-11-17 12:35:28 +01001487 return ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001488}
1489
Paul Cercueile3fbd952014-03-11 16:58:33 +01001490static int add_scan_elements(struct iio_device *dev, const char *devpath)
1491{
1492 struct stat st;
1493 char buf[1024];
1494 snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
1495
1496 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1497 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1498 if (ret < 0)
1499 return ret;
1500 }
1501
1502 return 0;
1503}
1504
Paul Cercueil1be57832014-03-11 16:27:16 +01001505static int create_device(void *d, const char *path)
1506{
Paul Cercueilff778232014-03-24 14:23:08 +01001507 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001508 unsigned int i;
1509 int ret;
1510 struct iio_context *ctx = d;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001511 struct iio_device *dev = zalloc(sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001512 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001513 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001514
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001515 dev->pdata = zalloc(sizeof(*dev->pdata));
Paul Cercueileaab6582014-02-21 09:35:59 +01001516 if (!dev->pdata) {
1517 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001518 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001519 }
1520
Romain Roffé6ce74a22015-06-30 11:45:11 +02001521 dev->pdata->fd = -1;
Romain Roffécead1da2015-06-30 13:35:51 +02001522 dev->pdata->blocking = true;
Romain Roffé0f737472015-06-30 16:45:54 +02001523 dev->pdata->nb_blocks = NB_BLOCKS;
Romain Roffé6ce74a22015-06-30 11:45:11 +02001524
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001525 dev->ctx = ctx;
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001526 dev->id = iio_strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001527 if (!dev->id) {
Romain Roffé0f737472015-06-30 16:45:54 +02001528 local_free_pdata(dev);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001529 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001530 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001531 }
1532
Paul Cercueil1be57832014-03-11 16:27:16 +01001533 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001534 if (ret < 0)
1535 goto err_free_device;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001536
Michael Hennerichebe49662014-11-07 10:32:44 +01001537 ret = add_scan_elements(dev, path);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001538 if (ret < 0)
1539 goto err_free_device;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001540
Paul Cercueilbab69a92015-07-03 11:24:17 +02001541 for (i = 0; i < dev->nb_channels; i++)
1542 set_channel_name(dev->channels[i]);
1543
Michael Hennerichebe49662014-11-07 10:32:44 +01001544 ret = detect_and_move_global_attrs(dev);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001545 if (ret < 0)
1546 goto err_free_device;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001547
Paul Cercueilff778232014-03-24 14:23:08 +01001548 dev->words = (dev->nb_channels + 31) / 32;
1549 if (dev->words) {
1550 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001551 if (!mask) {
Paul Cercueil290e0e02016-08-09 15:54:44 +02001552 ret = -ENOMEM;
1553 goto err_free_device;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001554 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001555 }
1556
Paul Cercueilff778232014-03-24 14:23:08 +01001557 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001558
Paul Cercueil1be57832014-03-11 16:27:16 +01001559 ret = add_device_to_context(ctx, dev);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001560 if (!ret)
1561 return 0;
1562
1563err_free_device:
1564 local_free_pdata(dev);
1565 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001566 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001567}
1568
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001569static int add_debug_attr(void *d, const char *path)
1570{
1571 struct iio_device *dev = d;
1572 const char *attr = strrchr(path, '/') + 1;
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001573 char **attrs, *name = iio_strdup(attr);
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001574 if (!name)
1575 return -ENOMEM;
1576
1577 attrs = realloc(dev->debug_attrs,
1578 (1 + dev->nb_debug_attrs) * sizeof(char *));
1579 if (!attrs) {
1580 free(name);
1581 return -ENOMEM;
1582 }
1583
1584 attrs[dev->nb_debug_attrs++] = name;
1585 dev->debug_attrs = attrs;
1586 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1587 return 0;
1588}
1589
1590static int add_debug(void *d, const char *path)
1591{
1592 struct iio_context *ctx = d;
1593 const char *name = strrchr(path, '/') + 1;
1594 struct iio_device *dev = iio_context_find_device(ctx, name);
1595 if (!dev)
1596 return -ENODEV;
1597 else
1598 return foreach_in_dir(dev, path, false, add_debug_attr);
1599}
1600
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001601static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1602{
Paul Cercueil00558f12016-04-12 14:40:40 +02001603 ctx->pdata->rw_timeout_ms = timeout;
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001604 return 0;
1605}
1606
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001607static void local_cancel(const struct iio_device *dev)
1608{
1609 struct iio_device_pdata *pdata = dev->pdata;
1610 uint64_t event = 1;
1611 int ret;
1612
1613 ret = write(pdata->cancel_fd, &event, sizeof(event));
1614 if (ret == -1) {
1615 /* If this happens something went very seriously wrong */
1616 char err_str[1024];
1617 iio_strerror(errno, err_str, sizeof(err_str));
1618 ERROR("Unable to signal cancellation event: %s\n", err_str);
1619 }
1620}
1621
Paul Cercueil0865e802014-10-28 14:35:19 +01001622static struct iio_context * local_clone(
1623 const struct iio_context *ctx __attribute__((unused)))
1624{
Paul Cercueil63e52182014-12-11 12:52:48 +01001625 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001626}
1627
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001628static const struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001629 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001630 .open = local_open,
1631 .close = local_close,
Romain Roffé87897862015-06-30 13:34:08 +02001632 .get_fd = local_get_fd,
Romain Roffécead1da2015-06-30 13:35:51 +02001633 .set_blocking_mode = local_set_blocking_mode,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001634 .read = local_read,
1635 .write = local_write,
Romain Roffé0f737472015-06-30 16:45:54 +02001636 .set_kernel_buffers_count = local_set_kernel_buffers_count,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001637 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001638 .read_device_attr = local_read_dev_attr,
1639 .write_device_attr = local_write_dev_attr,
1640 .read_channel_attr = local_read_chn_attr,
1641 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001642 .get_trigger = local_get_trigger,
1643 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001644 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001645 .set_timeout = local_set_timeout,
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001646 .cancel = local_cancel,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001647};
1648
Paul Cercueila1a34c62016-08-09 12:53:39 +02001649static void init_data_scale(struct iio_channel *chn)
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001650{
1651 char buf[1024];
1652 ssize_t ret;
1653
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001654 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1655 if (ret < 0) {
1656 chn->format.with_scale = false;
1657 } else {
1658 chn->format.with_scale = true;
1659 chn->format.scale = atof(buf);
1660 }
1661}
1662
1663static void init_scan_elements(struct iio_context *ctx)
1664{
1665 unsigned int i, j;
1666
1667 for (i = 0; i < ctx->nb_devices; i++) {
1668 struct iio_device *dev = ctx->devices[i];
1669
Paul Cercueila1a34c62016-08-09 12:53:39 +02001670 for (j = 0; j < dev->nb_channels; j++)
1671 init_data_scale(dev->channels[j]);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001672 }
1673}
1674
Paul Cercueil63e52182014-12-11 12:52:48 +01001675struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001676{
Paul Cercueilfd387472015-08-05 10:34:19 +02001677 int ret = -ENOMEM;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001678 unsigned int len;
1679 struct utsname uts;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001680 struct iio_context *ctx = zalloc(sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001681 if (!ctx)
Paul Cercueilfd387472015-08-05 10:34:19 +02001682 goto err_set_errno;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001683
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001684 ctx->ops = &local_ops;
1685 ctx->name = "local";
Paul Cercueil00558f12016-04-12 14:40:40 +02001686
1687 ctx->pdata = zalloc(sizeof(*ctx->pdata));
1688 if (!ctx->pdata) {
1689 free(ctx);
1690 goto err_set_errno;
1691 }
1692
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001693 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001694
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001695 uname(&uts);
1696 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
1697 + strlen(uts.version) + strlen(uts.machine);
1698 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
1699 if (!ctx->description) {
Paul Cercueil00558f12016-04-12 14:40:40 +02001700 free(ctx->pdata);
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001701 free(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001702 goto err_set_errno;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001703 }
1704
1705 snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
1706 uts.nodename, uts.release, uts.version, uts.machine);
1707
Paul Cercueil1be57832014-03-11 16:27:16 +01001708 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
Paul Cercueilfd387472015-08-05 10:34:19 +02001709 if (ret < 0)
1710 goto err_context_destroy;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001711
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001712 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001713
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001714 init_scan_elements(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02001715 ret = iio_context_init(ctx);
1716 if (ret < 0)
1717 goto err_context_destroy;
Paul Cercueilae88fde2014-03-12 11:47:10 +01001718
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001719 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001720
Paul Cercueilfd387472015-08-05 10:34:19 +02001721err_context_destroy:
1722 iio_context_destroy(ctx);
1723err_set_errno:
1724 errno = -ret;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001725 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001726}
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001727
1728static int check_device(void *d, const char *path)
1729{
1730 *(bool *)d = true;
1731 return 0;
1732}
1733
1734int local_context_scan(struct iio_scan_result *scan_result)
1735{
1736 struct iio_context_info **info;
1737 bool exists = false;
Paul Cercueil6303ca22016-11-10 16:55:40 +01001738 char *desc, *uri;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001739 int ret;
1740
1741 ret = foreach_in_dir(&exists, "/sys/bus/iio/devices",
1742 true, check_device);
1743 if (ret < 0 || !exists)
1744 return 0;
1745
Paul Cercueil6303ca22016-11-10 16:55:40 +01001746 desc = iio_strdup("Local devices");
1747 if (!desc)
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001748 return -ENOMEM;
1749
Paul Cercueil6303ca22016-11-10 16:55:40 +01001750 uri = iio_strdup("local:");
1751 if (!uri)
1752 goto err_free_desc;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001753
Paul Cercueil6303ca22016-11-10 16:55:40 +01001754 info = iio_scan_result_add(scan_result, 1);
1755 if (!info)
1756 goto err_free_uri;
1757
1758 info[0]->description = desc;
1759 info[0]->uri = uri;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001760 return 0;
Paul Cercueil6303ca22016-11-10 16:55:40 +01001761
1762err_free_uri:
1763 free(uri);
1764err_free_desc:
1765 free(desc);
1766 return -ENOMEM;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02001767}