blob: 249da1ee921dc165f505549b763feaae9ca203fe [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"
Robin Getz57295ce2018-05-24 21:45:08 +000021#include "sort.h"
Paul Cercueil0b2ce712014-02-17 15:04:18 +010022
Paul Cercueil1be57832014-03-11 16:27:16 +010023#include <dirent.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010024#include <errno.h>
Lars-Peter Clausenea5ea6f2016-04-21 18:23:38 +020025#include <limits.h>
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020026#include <poll.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010027#include <stdbool.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010028#include <stddef.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010029#include <stdio.h>
30#include <string.h>
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +020031#include <sys/eventfd.h>
Paul Cercueil92f46df2014-04-28 13:17:53 +020032#include <sys/ioctl.h>
33#include <sys/mman.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010034#include <sys/types.h>
35#include <sys/stat.h>
36#include <unistd.h>
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +020037#include <string.h>
Lars-Peter Clausen00f80092014-07-01 17:52:05 +020038#include <sys/utsname.h>
Lars-Peter Clausenb22da002016-04-21 14:58:53 +020039#include <time.h>
Romain Roffécead1da2015-06-30 13:35:51 +020040#include <unistd.h>
Romain Roffé6ce74a22015-06-30 11:45:11 +020041#include <fcntl.h>
Paul Cercueile6be0702016-11-18 10:57:23 +010042#ifdef WITH_LOCAL_CONFIG
43#include <ini.h>
44#endif
Paul Cercueil0b2ce712014-02-17 15:04:18 +010045
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020046#define DEFAULT_TIMEOUT_MS 1000
47
Paul Cercueil92f46df2014-04-28 13:17:53 +020048#define NB_BLOCKS 4
49
50#define BLOCK_ALLOC_IOCTL _IOWR('i', 0xa0, struct block_alloc_req)
51#define BLOCK_FREE_IOCTL _IO('i', 0xa1)
52#define BLOCK_QUERY_IOCTL _IOWR('i', 0xa2, struct block)
53#define BLOCK_ENQUEUE_IOCTL _IOWR('i', 0xa3, struct block)
54#define BLOCK_DEQUEUE_IOCTL _IOWR('i', 0xa4, struct block)
55
Paul Cercueil71694c72014-05-22 14:02:13 +020056#define BLOCK_FLAG_CYCLIC BIT(1)
57
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020058/* Forward declarations */
59static ssize_t local_read_dev_attr(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -050060 const char *attr, char *dst, size_t len, enum iio_attr_type type);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020061static ssize_t local_read_chn_attr(const struct iio_channel *chn,
62 const char *attr, char *dst, size_t len);
Paul Cercueil1da28122014-05-22 10:59:49 +020063static ssize_t local_write_dev_attr(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -050064 const char *attr, const char *src, size_t len, enum iio_attr_type type);
Paul Cercueil1da28122014-05-22 10:59:49 +020065static ssize_t local_write_chn_attr(const struct iio_channel *chn,
66 const char *attr, const char *src, size_t len);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020067
Paul Cercueil92f46df2014-04-28 13:17:53 +020068struct block_alloc_req {
69 uint32_t type,
70 size,
71 count,
72 id;
73};
74
75struct block {
76 uint32_t id,
77 size,
78 bytes_used,
79 type,
80 flags,
81 offset;
82 uint64_t timestamp;
83};
84
Paul Cercueil00558f12016-04-12 14:40:40 +020085struct iio_context_pdata {
Lars-Peter Clausen8068be32016-04-22 10:36:34 +020086 unsigned int rw_timeout_ms;
Paul Cercueil00558f12016-04-12 14:40:40 +020087};
88
Paul Cercueileaab6582014-02-21 09:35:59 +010089struct iio_device_pdata {
Romain Roffé6ce74a22015-06-30 11:45:11 +020090 int fd;
Romain Roffécead1da2015-06-30 13:35:51 +020091 bool blocking;
Lars-Peter Clausen23605a32017-11-15 13:23:54 +010092 unsigned int samples_count;
93 unsigned int max_nb_blocks;
94 unsigned int allocated_nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +020095
Romain Roffé0f737472015-06-30 16:45:54 +020096 struct block *blocks;
97 void **addrs;
Paul Cercueil92f46df2014-04-28 13:17:53 +020098 int last_dequeued;
Paul Cercueil6ea8a752014-06-03 11:35:35 +020099 bool is_high_speed, cyclic, cyclic_buffer_enqueued, buffer_enabled;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200100
101 int cancel_fd;
Paul Cercueileaab6582014-02-21 09:35:59 +0100102};
103
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200104struct iio_channel_pdata {
Paul Cercueila1a34c62016-08-09 12:53:39 +0200105 char *enable_fn;
Paul Cercueil54e96cc2016-12-19 12:27:25 +0100106 struct iio_channel_attr *protected_attrs;
107 unsigned int nb_protected_attrs;
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200108};
109
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100110static const char * const device_attrs_blacklist[] = {
111 "dev",
112 "uevent",
113};
114
Matt Fornero7f9598f2017-11-30 14:07:52 -0500115static const char * const buffer_attrs_reserved[] = {
116 "length",
117 "enable",
118};
119
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200120static int ioctl_nointr(int fd, unsigned long request, void *data)
121{
122 int ret;
123
124 do {
125 ret = ioctl(fd, request, data);
126 } while (ret == -1 && errno == EINTR);
127
128 return ret;
129}
130
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200131static void local_free_channel_pdata(struct iio_channel *chn)
132{
Paul Cercueila1a34c62016-08-09 12:53:39 +0200133 if (chn->pdata) {
134 free(chn->pdata->enable_fn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200135 free(chn->pdata);
Paul Cercueila1a34c62016-08-09 12:53:39 +0200136 }
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200137}
138
Romain Roffé0f737472015-06-30 16:45:54 +0200139static void local_free_pdata(struct iio_device *device)
140{
Paul Cercueil3f9dcb02016-08-09 17:16:25 +0200141 unsigned int i;
142
143 for (i = 0; i < device->nb_channels; i++)
144 local_free_channel_pdata(device->channels[i]);
145
146 if (device->pdata) {
Romain Roffé0f737472015-06-30 16:45:54 +0200147 free(device->pdata->blocks);
148 free(device->pdata->addrs);
149 free(device->pdata);
150 }
151}
152
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100153static void local_shutdown(struct iio_context *ctx)
154{
Paul Cercueil42d12352014-05-05 16:11:58 +0200155 /* Free the backend data stored in every device structure */
Paul Cercueil167d3112014-02-18 12:23:53 +0100156 unsigned int i;
Paul Cercueil00558f12016-04-12 14:40:40 +0200157
Paul Cercueilb04d4d12016-08-01 15:46:06 +0200158 for (i = 0; i < ctx->nb_devices; i++) {
159 struct iio_device *dev = ctx->devices[i];
160
161 iio_device_close(dev);
162 local_free_pdata(dev);
163 }
Paul Cercueil00558f12016-04-12 14:40:40 +0200164
165 free(ctx->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100166}
167
Michael Hennerich1c8aa572014-11-06 17:42:30 +0100168/** Shrinks the first nb characters of a string
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100169 * e.g. strcut("foobar", 4) replaces the content with "ar". */
170static void strcut(char *str, int nb)
171{
172 char *ptr = str + nb;
173 while (*ptr)
174 *str++ = *ptr++;
175 *str = 0;
176}
177
178static int set_channel_name(struct iio_channel *chn)
179{
Paul Cercueil54e96cc2016-12-19 12:27:25 +0100180 struct iio_channel_pdata *pdata = chn->pdata;
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100181 size_t prefix_len = 0;
182 const char *attr0;
183 const char *ptr;
184 unsigned int i;
185
Paul Cercueil54e96cc2016-12-19 12:27:25 +0100186 if (chn->nb_attrs + pdata->nb_protected_attrs < 2)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100187 return 0;
188
Paul Cercueil54e96cc2016-12-19 12:27:25 +0100189 if (chn->nb_attrs)
190 attr0 = ptr = chn->attrs[0].name;
191 else
192 attr0 = ptr = pdata->protected_attrs[0].name;
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100193
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100194 while (true) {
195 bool can_fix = true;
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100196 size_t len;
197
198 ptr = strchr(ptr, '_');
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100199 if (!ptr)
200 break;
201
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100202 len = ptr - attr0 + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100203 for (i = 1; can_fix && i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200204 can_fix = !strncmp(attr0, chn->attrs[i].name, len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100205
Paul Cercueil54e96cc2016-12-19 12:27:25 +0100206 for (i = !chn->nb_attrs;
207 can_fix && i < pdata->nb_protected_attrs; i++) {
208 can_fix = !strncmp(attr0,
209 pdata->protected_attrs[i].name, len);
210 }
211
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100212 if (!can_fix)
213 break;
214
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100215 prefix_len = len;
216 ptr = ptr + 1;
217 }
218
219 if (prefix_len) {
220 char *name;
221
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100222 name = malloc(prefix_len);
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100223 if (!name)
224 return -ENOMEM;
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100225 strncpy(name, attr0, prefix_len - 1);
226 name[prefix_len - 1] = '\0';
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100227 DEBUG("Setting name of channel %s to %s\n", chn->id, name);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100228 chn->name = name;
229
230 /* Shrink the attribute name */
231 for (i = 0; i < chn->nb_attrs; i++)
Lars-Peter Clauseneec8cf82016-01-25 16:02:02 +0100232 strcut(chn->attrs[i].name, prefix_len);
Paul Cercueil54e96cc2016-12-19 12:27:25 +0100233 for (i = 0; i < pdata->nb_protected_attrs; i++)
234 strcut(pdata->protected_attrs[i].name, prefix_len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100235 }
236
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100237 return 0;
238}
239
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200240/*
241 * Used to generate the timeout parameter for operations like poll. Returns the
242 * number of ms until it is timeout_rel ms after the time specified in start. If
243 * timeout_rel is 0 returns -1 to indicate no timeout.
244 *
245 * The timeout that is specified for IIO operations is the maximum time a buffer
246 * push() or refill() operation should take before returning. poll() is used to
247 * wait for either data activity or for the timeout to elapse. poll() might get
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200248 * interrupted in which case it is called again or the read()/write() operation
249 * might not complete the full buffer size in one call in which case we go back
250 * to poll() again as well. Passing the same timeout as before would increase
251 * the total timeout and if repeated interruptions occur (e.g. by a timer
252 * signal) the operation might never time out or with significant delay. Hence
253 * before each poll() invocation the timeout is recalculated relative to the
254 * start of refill() or push() operation.
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200255 */
256static int get_rel_timeout_ms(struct timespec *start, unsigned int timeout_rel)
257{
258 struct timespec now;
259 int diff_ms;
260
261 if (timeout_rel == 0) /* No timeout */
262 return -1;
263
264 clock_gettime(CLOCK_MONOTONIC, &now);
265
266 diff_ms = (now.tv_sec - start->tv_sec) * 1000;
267 diff_ms += (now.tv_nsec - start->tv_nsec) / 1000000;
268
269 if (diff_ms >= timeout_rel) /* Expired */
270 return 0;
271 if (diff_ms > 0) /* Should never be false, but lets be safe */
272 timeout_rel -= diff_ms;
273 if (timeout_rel > INT_MAX)
274 return INT_MAX;
275
276 return (int) timeout_rel;
277}
278
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200279static int device_check_ready(const struct iio_device *dev, short events,
280 struct timespec *start)
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200281{
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200282 struct pollfd pollfd[2] = {
283 {
284 .fd = dev->pdata->fd,
285 .events = events,
286 }, {
287 .fd = dev->pdata->cancel_fd,
288 .events = POLLIN,
289 }
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200290 };
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200291 unsigned int rw_timeout_ms = dev->ctx->pdata->rw_timeout_ms;
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200292 int timeout_rel;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200293 int ret;
294
Romain Roffécead1da2015-06-30 13:35:51 +0200295 if (!dev->pdata->blocking)
296 return 0;
297
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200298 do {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200299 timeout_rel = get_rel_timeout_ms(start, rw_timeout_ms);
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200300 ret = poll(pollfd, 2, timeout_rel);
Lars-Peter Clausenb22da002016-04-21 14:58:53 +0200301 } while (ret == -1 && errno == EINTR);
302
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200303 if ((pollfd[1].revents & POLLIN))
304 return -EBADF;
305
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200306 if (ret < 0)
307 return -errno;
308 if (!ret)
309 return -ETIMEDOUT;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200310 if (pollfd[0].revents & POLLNVAL)
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200311 return -EBADF;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200312 if (!(pollfd[0].revents & events))
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200313 return -EIO;
314 return 0;
315}
316
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200317static ssize_t local_read(const struct iio_device *dev,
318 void *dst, size_t len, uint32_t *mask, size_t words)
Romain Roffé6ce74a22015-06-30 11:45:11 +0200319{
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200320 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200321 uintptr_t ptr = (uintptr_t) dst;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200322 struct timespec start;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200323 ssize_t readsize;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200324 ssize_t ret;
325
326 if (pdata->fd == -1)
327 return -EBADF;
328 if (words != dev->words)
329 return -EINVAL;
330
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200331 memcpy(mask, dev->mask, words);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200332
Lars-Peter Clausen8ba0d5b2016-02-17 11:30:23 +0100333 if (len == 0)
334 return 0;
335
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200336 clock_gettime(CLOCK_MONOTONIC, &start);
Lars-Peter Clausen525c93e2016-04-21 14:05:27 +0200337
Romain Roffé6ce74a22015-06-30 11:45:11 +0200338 while (len > 0) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200339 ret = device_check_ready(dev, POLLIN, &start);
340 if (ret < 0)
341 break;
342
Romain Roffé6ce74a22015-06-30 11:45:11 +0200343 do {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200344 ret = read(pdata->fd, (void *) ptr, len);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200345 } while (ret == -1 && errno == EINTR);
346
347 if (ret == -1) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200348 if (pdata->blocking && errno == EAGAIN)
349 continue;
Rémi Lefèvrea9ef6762016-12-19 16:29:38 +0100350 ret = -errno;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200351 break;
352 } else if (ret == 0) {
353 ret = -EIO;
354 break;
355 }
356
357 ptr += ret;
358 len -= ret;
359 }
360
361 readsize = (ssize_t)(ptr - (uintptr_t) dst);
Romain Roffécead1da2015-06-30 13:35:51 +0200362 if ((ret > 0 || ret == -EAGAIN) && (readsize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200363 return readsize;
364 else
365 return ret;
366}
367
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200368static ssize_t local_write(const struct iio_device *dev,
369 const void *src, size_t len)
Romain Roffé6ce74a22015-06-30 11:45:11 +0200370{
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200371 struct iio_device_pdata *pdata = dev->pdata;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200372 uintptr_t ptr = (uintptr_t) src;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200373 struct timespec start;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200374 ssize_t writtensize;
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200375 ssize_t ret;
376
377 if (pdata->fd == -1)
378 return -EBADF;
379
Lars-Peter Clausen525c93e2016-04-21 14:05:27 +0200380 if (len == 0)
381 return 0;
382
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200383 clock_gettime(CLOCK_MONOTONIC, &start);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200384
385 while (len > 0) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200386 ret = device_check_ready(dev, POLLOUT, &start);
387 if (ret < 0)
388 break;
389
Romain Roffé6ce74a22015-06-30 11:45:11 +0200390 do {
Lars-Peter Clausen819d3102016-04-21 14:02:09 +0200391 ret = write(pdata->fd, (void *) ptr, len);
Romain Roffé6ce74a22015-06-30 11:45:11 +0200392 } while (ret == -1 && errno == EINTR);
393
394 if (ret == -1) {
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200395 if (pdata->blocking && errno == EAGAIN)
396 continue;
397
Rémi Lefèvrea9ef6762016-12-19 16:29:38 +0100398 ret = -errno;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200399 break;
400 } else if (ret == 0) {
401 ret = -EIO;
402 break;
403 }
404
405 ptr += ret;
406 len -= ret;
407 }
408
409 writtensize = (ssize_t)(ptr - (uintptr_t) src);
Romain Roffécead1da2015-06-30 13:35:51 +0200410 if ((ret > 0 || ret == -EAGAIN) && (writtensize > 0))
Romain Roffé6ce74a22015-06-30 11:45:11 +0200411 return writtensize;
412 else
413 return ret;
414}
415
Romain Roffécead1da2015-06-30 13:35:51 +0200416static ssize_t local_enable_buffer(const struct iio_device *dev)
417{
418 struct iio_device_pdata *pdata = dev->pdata;
419 ssize_t ret = 0;
420
421 if (!pdata->buffer_enabled) {
422 ret = local_write_dev_attr(dev,
423 "buffer/enable", "1", 2, false);
424 if (ret >= 0)
425 pdata->buffer_enabled = true;
426 }
427
Robin Getz79ccac82018-10-30 17:49:22 -0400428 return ret;
Romain Roffécead1da2015-06-30 13:35:51 +0200429}
Romain Roffé6ce74a22015-06-30 11:45:11 +0200430
Romain Roffé0f737472015-06-30 16:45:54 +0200431static int local_set_kernel_buffers_count(const struct iio_device *dev,
432 unsigned int nb_blocks)
433{
434 struct iio_device_pdata *pdata = dev->pdata;
435
436 if (pdata->fd != -1)
437 return -EBUSY;
438
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100439 pdata->max_nb_blocks = nb_blocks;
Romain Roffé0f737472015-06-30 16:45:54 +0200440
441 return 0;
442}
443
Paul Cercueil92f46df2014-04-28 13:17:53 +0200444static ssize_t local_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100445 void **addr_ptr, size_t bytes_used,
446 uint32_t *mask, size_t words)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200447{
448 struct block block;
449 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200450 struct timespec start;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200451 char err_str[1024];
Romain Roffé6ce74a22015-06-30 11:45:11 +0200452 int f = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200453 ssize_t ret;
454
455 if (!pdata->is_high_speed)
456 return -ENOSYS;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200457 if (f == -1)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200458 return -EBADF;
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200459 if (!addr_ptr)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200460 return -EINVAL;
461
Paul Cercueil92f46df2014-04-28 13:17:53 +0200462 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200463 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200464
465 if (pdata->cyclic) {
466 if (pdata->cyclic_buffer_enqueued)
467 return -EBUSY;
468 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
469 pdata->cyclic_buffer_enqueued = true;
470 }
471
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200472 last_block->bytes_used = bytes_used;
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200473 ret = (ssize_t) ioctl_nointr(f,
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200474 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200475 if (ret) {
476 ret = (ssize_t) -errno;
Lars-Peter Clausen3417a1a2016-04-18 14:29:02 +0200477 iio_strerror(errno, err_str, sizeof(err_str));
478 ERROR("Unable to enqueue block: %s\n", err_str);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200479 return ret;
480 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200481
482 if (pdata->cyclic) {
483 *addr_ptr = pdata->addrs[pdata->last_dequeued];
484 return (ssize_t) last_block->bytes_used;
485 }
Markus Gnadl6991e292017-12-19 13:55:52 +0100486
487 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200488 }
489
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200490 clock_gettime(CLOCK_MONOTONIC, &start);
Lars-Peter Clausene63811e2016-04-21 11:22:33 +0200491
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200492 do {
493 ret = (ssize_t) device_check_ready(dev, POLLIN | POLLOUT, &start);
494 if (ret < 0)
495 return ret;
496
497 memset(&block, 0, sizeof(block));
498 ret = (ssize_t) ioctl_nointr(f, BLOCK_DEQUEUE_IOCTL, &block);
499 } while (pdata->blocking && ret == -1 && errno == EAGAIN);
500
Paul Cercueil92f46df2014-04-28 13:17:53 +0200501 if (ret) {
502 ret = (ssize_t) -errno;
Paul Cercueilea51a3f2016-05-25 17:22:03 +0200503 if ((!pdata->blocking && ret != -EAGAIN) ||
504 (pdata->blocking && ret != -ETIMEDOUT)) {
Lars-Peter Clausenf8408352016-04-25 10:43:11 +0200505 iio_strerror(errno, err_str, sizeof(err_str));
506 ERROR("Unable to dequeue block: %s\n", err_str);
507 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200508 return ret;
509 }
510
Paul Cercueil558ade42014-11-27 10:59:48 +0100511 /* Requested buffer size is too big! */
Dan Nechitaed45c962020-02-04 10:56:42 +0200512 if (pdata->last_dequeued < 0 && bytes_used > block.size)
Paul Cercueil558ade42014-11-27 10:59:48 +0100513 return -EFBIG;
514
Paul Cercueil92f46df2014-04-28 13:17:53 +0200515 pdata->last_dequeued = block.id;
516 *addr_ptr = pdata->addrs[block.id];
517 return (ssize_t) block.bytes_used;
518}
519
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200520static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -0500521 char *dst, size_t len, enum iio_attr_type type)
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200522{
Matt Fornero81f04a52017-11-30 14:36:37 -0500523 unsigned int i, nb;
524 char **attrs;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200525 char *ptr = dst;
526
Matt Fornero81f04a52017-11-30 14:36:37 -0500527 switch (type) {
528 case IIO_ATTR_TYPE_DEVICE:
529 nb = dev->nb_attrs;
530 attrs = dev->attrs;
531 break;
532 case IIO_ATTR_TYPE_DEBUG:
533 nb = dev->nb_debug_attrs;
534 attrs = dev->debug_attrs;
535 break;
536 case IIO_ATTR_TYPE_BUFFER:
537 nb = dev->nb_buffer_attrs;
538 attrs = dev->buffer_attrs;
539 break;
540 default:
541 return -EINVAL;
542 break;
543 }
544
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200545 for (i = 0; len >= 4 && i < nb; i++) {
546 /* Recursive! */
547 ssize_t ret = local_read_dev_attr(dev, attrs[i],
Matt Fornero81f04a52017-11-30 14:36:37 -0500548 ptr + 4, len - 4, type);
Paul Cercueil2042c902016-04-25 18:43:45 +0200549 *(uint32_t *) ptr = iio_htobe32(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200550
551 /* Align the length to 4 bytes */
552 if (ret > 0 && ret & 3)
553 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200554 ptr += 4 + (ret < 0 ? 0 : ret);
555 len -= 4 + (ret < 0 ? 0 : ret);
556 }
557
558 return ptr - dst;
559}
560
561static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
562 char *dst, size_t len)
563{
564 unsigned int i;
565 char *ptr = dst;
566
567 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
568 /* Recursive! */
569 ssize_t ret = local_read_chn_attr(chn,
570 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil2042c902016-04-25 18:43:45 +0200571 *(uint32_t *) ptr = iio_htobe32(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200572
573 /* Align the length to 4 bytes */
574 if (ret > 0 && ret & 3)
575 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200576 ptr += 4 + (ret < 0 ? 0 : ret);
577 len -= 4 + (ret < 0 ? 0 : ret);
578 }
579
580 return ptr - dst;
581}
582
Paul Cercueil1da28122014-05-22 10:59:49 +0200583static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
584{
585 while (nb--) {
586 int32_t val;
587
588 if (len < 4)
589 return -EINVAL;
590
Paul Cercueil2042c902016-04-25 18:43:45 +0200591 val = (int32_t) iio_be32toh(*(uint32_t *) src);
Paul Cercueil1da28122014-05-22 10:59:49 +0200592 src += 4;
593 len -= 4;
594
595 if (val > 0) {
596 if ((uint32_t) val > len)
597 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200598
599 /* Align the length to 4 bytes */
600 if (val & 3)
601 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200602 len -= val;
603 src += val;
604 }
605 }
606
607 /* We should have analyzed the whole buffer by now */
608 return !len ? 0 : -EINVAL;
609}
610
611static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -0500612 const char *src, size_t len, enum iio_attr_type type)
Paul Cercueil1da28122014-05-22 10:59:49 +0200613{
Matt Fornero81f04a52017-11-30 14:36:37 -0500614 unsigned int i, nb;
615 char **attrs;
Paul Cercueil1da28122014-05-22 10:59:49 +0200616 const char *ptr = src;
617
Matt Fornero81f04a52017-11-30 14:36:37 -0500618 switch (type) {
619 case IIO_ATTR_TYPE_DEVICE:
620 nb = dev->nb_attrs;
621 attrs = dev->attrs;
622 break;
623 case IIO_ATTR_TYPE_DEBUG:
624 nb = dev->nb_debug_attrs;
625 attrs = dev->debug_attrs;
626 break;
627 case IIO_ATTR_TYPE_BUFFER:
628 nb = dev->nb_buffer_attrs;
629 attrs = dev->buffer_attrs;
630 break;
631 default:
632 return -EINVAL;
633 break;
634 }
635
Paul Cercueil1da28122014-05-22 10:59:49 +0200636 /* First step: Verify that the buffer is in the correct format */
637 if (local_buffer_analyze(nb, src, len))
638 return -EINVAL;
639
640 /* Second step: write the attributes */
641 for (i = 0; i < nb; i++) {
Paul Cercueil2042c902016-04-25 18:43:45 +0200642 int32_t val = (int32_t) iio_be32toh(*(uint32_t *) ptr);
Paul Cercueil1da28122014-05-22 10:59:49 +0200643 ptr += 4;
644
645 if (val > 0) {
Matt Fornero81f04a52017-11-30 14:36:37 -0500646 local_write_dev_attr(dev, attrs[i], ptr, val, type);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200647
648 /* Align the length to 4 bytes */
649 if (val & 3)
650 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200651 ptr += val;
652 }
653 }
654
655 return ptr - src;
656}
657
658static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
659 const char *src, size_t len)
660{
661 unsigned int i, nb = chn->nb_attrs;
662 const char *ptr = src;
663
664 /* First step: Verify that the buffer is in the correct format */
665 if (local_buffer_analyze(nb, src, len))
666 return -EINVAL;
667
668 /* Second step: write the attributes */
669 for (i = 0; i < nb; i++) {
Paul Cercueil2042c902016-04-25 18:43:45 +0200670 int32_t val = (int32_t) iio_be32toh(*(uint32_t *) ptr);
Paul Cercueil1da28122014-05-22 10:59:49 +0200671 ptr += 4;
672
673 if (val > 0) {
674 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200675
676 /* Align the length to 4 bytes */
677 if (val & 3)
678 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200679 ptr += val;
680 }
681 }
682
683 return ptr - src;
684}
685
Paul Cercueil167d3112014-02-18 12:23:53 +0100686static ssize_t local_read_dev_attr(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -0500687 const char *attr, char *dst, size_t len, enum iio_attr_type type)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100688{
Paul Cercueil3e898302014-02-17 16:17:11 +0100689 FILE *f;
690 char buf[1024];
691 ssize_t ret;
692
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200693 if (!attr)
Matt Fornero81f04a52017-11-30 14:36:37 -0500694 return local_read_all_dev_attrs(dev, dst, len, type);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200695
Matt Fornero81f04a52017-11-30 14:36:37 -0500696 switch (type) {
697 case IIO_ATTR_TYPE_DEVICE:
698 iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
699 dev->id, attr);
700 break;
701 case IIO_ATTR_TYPE_DEBUG:
702 iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
703 dev->id, attr);
704 break;
705 case IIO_ATTR_TYPE_BUFFER:
706 iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/buffer/%s",
707 dev->id, attr);
708 break;
709 default:
710 return -EINVAL;
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100711 }
712
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100713 f = fopen(buf, "re");
Paul Cercueil3e898302014-02-17 16:17:11 +0100714 if (!f)
715 return -errno;
716
717 ret = fread(dst, 1, len, f);
718 if (ret > 0)
719 dst[ret - 1] = '\0';
Adrian Suciu8edf0a22019-07-09 12:20:22 +0300720 else
721 dst[0] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100722 fflush(f);
723 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200724 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100725 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200726 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100727}
728
Paul Cercueil167d3112014-02-18 12:23:53 +0100729static ssize_t local_write_dev_attr(const struct iio_device *dev,
Matt Fornero81f04a52017-11-30 14:36:37 -0500730 const char *attr, const char *src, size_t len, enum iio_attr_type type)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100731{
Paul Cercueil3e898302014-02-17 16:17:11 +0100732 FILE *f;
733 char buf[1024];
734 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100735
Paul Cercueil1da28122014-05-22 10:59:49 +0200736 if (!attr)
Matt Fornero81f04a52017-11-30 14:36:37 -0500737 return local_write_all_dev_attrs(dev, src, len, type);
Paul Cercueil1da28122014-05-22 10:59:49 +0200738
Matt Fornero81f04a52017-11-30 14:36:37 -0500739 switch (type) {
740 case IIO_ATTR_TYPE_DEVICE:
741 iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
742 dev->id, attr);
743 break;
744 case IIO_ATTR_TYPE_DEBUG:
745 iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
746 dev->id, attr);
747 break;
748 case IIO_ATTR_TYPE_BUFFER:
749 iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/buffer/%s",
750 dev->id, attr);
751 break;
752 default:
753 return -EINVAL;
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100754 }
755
Lars-Peter Clausene7917742016-02-11 14:49:16 +0100756 f = fopen(buf, "we");
Paul Cercueil3e898302014-02-17 16:17:11 +0100757 if (!f)
758 return -errno;
759
760 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100761 fflush(f);
762 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200763 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100764 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200765 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100766}
767
Paul Cercueil167d3112014-02-18 12:23:53 +0100768static const char * get_filename(const struct iio_channel *chn,
769 const char *attr)
770{
Paul Cercueil167d3112014-02-18 12:23:53 +0100771 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200772 for (i = 0; i < chn->nb_attrs; i++)
773 if (!strcmp(attr, chn->attrs[i].name))
774 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100775 return attr;
776}
777
778static ssize_t local_read_chn_attr(const struct iio_channel *chn,
779 const char *attr, char *dst, size_t len)
780{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200781 if (!attr)
782 return local_read_all_chn_attrs(chn, dst, len);
783
Paul Cercueil167d3112014-02-18 12:23:53 +0100784 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200785 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100786}
787
788static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200789 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100790{
Paul Cercueil1da28122014-05-22 10:59:49 +0200791 if (!attr)
792 return local_write_all_chn_attrs(chn, src, len);
793
Paul Cercueil167d3112014-02-18 12:23:53 +0100794 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200795 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100796}
797
Lars-Peter Clausen1302f962017-08-10 09:52:58 +0200798static int channel_write_state(const struct iio_channel *chn, bool en)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100799{
Paul Cercueila1a34c62016-08-09 12:53:39 +0200800 ssize_t ret;
801
Paul Cercueil270f3042017-04-11 17:28:59 +0200802 if (!chn->pdata->enable_fn) {
Paul Cercueila1a34c62016-08-09 12:53:39 +0200803 ERROR("Libiio bug: No \"en\" attribute parsed\n");
804 return -EINVAL;
805 }
806
Lars-Peter Clausen1302f962017-08-10 09:52:58 +0200807 ret = local_write_chn_attr(chn, chn->pdata->enable_fn, en ? "1" : "0", 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100808 if (ret < 0)
809 return (int) ret;
810 else
811 return 0;
812}
813
Paul Cercueil92f46df2014-04-28 13:17:53 +0200814static int enable_high_speed(const struct iio_device *dev)
815{
816 struct block_alloc_req req;
817 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100818 unsigned int nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200819 unsigned int i;
Romain Roffé6ce74a22015-06-30 11:45:11 +0200820 int ret, fd = pdata->fd;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200821
Lars-Peter Clausen9ff8c7a2018-05-02 14:04:55 +0200822 /*
823 * For the BLOCK_ALLOC_IOCTL ioctl it is not possible to distingush
824 * between an error during the allocation (e.g. incorrect size) or
825 * whether the high-speed interface is not supported. BLOCK_FREE_IOCTL does
826 * never fail if the device supports the high-speed interface, so we use it
827 * here. Calling it when no blocks are allocated the ioctl has no effect.
828 */
829 ret = ioctl_nointr(fd, BLOCK_FREE_IOCTL, NULL);
830 if (ret < 0)
831 return -ENOSYS;
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100832
Paul Cercueil71694c72014-05-22 14:02:13 +0200833 if (pdata->cyclic) {
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100834 nb_blocks = 1;
Paul Cercueil71694c72014-05-22 14:02:13 +0200835 DEBUG("Enabling cyclic mode\n");
836 } else {
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100837 nb_blocks = pdata->max_nb_blocks;
Paul Cercueil71694c72014-05-22 14:02:13 +0200838 DEBUG("Cyclic mode not enabled\n");
839 }
840
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100841 pdata->blocks = calloc(nb_blocks, sizeof(*pdata->blocks));
842 if (!pdata->blocks)
Romain Roffé0f737472015-06-30 16:45:54 +0200843 return -ENOMEM;
Romain Roffé0f737472015-06-30 16:45:54 +0200844
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100845 pdata->addrs = calloc(nb_blocks, sizeof(*pdata->addrs));
Romain Roffé0f737472015-06-30 16:45:54 +0200846 if (!pdata->addrs) {
847 free(pdata->blocks);
848 pdata->blocks = NULL;
849 return -ENOMEM;
850 }
851
Paul Cercueil1fa913d2015-04-28 16:30:53 +0200852 req.id = 0;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200853 req.type = 0;
854 req.size = pdata->samples_count *
855 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100856 req.count = nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200857
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200858 ret = ioctl_nointr(fd, BLOCK_ALLOC_IOCTL, &req);
Romain Roffé0f737472015-06-30 16:45:54 +0200859 if (ret < 0) {
860 ret = -errno;
861 goto err_freemem;
862 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200863
Lars-Peter Clausen55526432017-11-15 13:24:46 +0100864 if (req.count == 0) {
865 ret = -ENOMEM;
866 goto err_block_free;
867 }
868
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200869 /* We might get less blocks than what we asked for */
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100870 pdata->allocated_nb_blocks = req.count;
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200871
Paul Cercueil92f46df2014-04-28 13:17:53 +0200872 /* mmap all the blocks */
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100873 for (i = 0; i < pdata->allocated_nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200874 pdata->blocks[i].id = i;
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200875 ret = ioctl_nointr(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200876 if (ret) {
877 ret = -errno;
878 goto err_munmap;
879 }
880
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200881 ret = ioctl_nointr(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200882 if (ret) {
883 ret = -errno;
884 goto err_munmap;
885 }
886
Paul Cercueil032a5652014-05-12 17:11:19 +0200887 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
888 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200889 MAP_SHARED, fd, pdata->blocks[i].offset);
890 if (pdata->addrs[i] == MAP_FAILED) {
891 ret = -errno;
892 goto err_munmap;
893 }
894 }
895
Paul Cercueil4a702d32014-05-12 17:02:37 +0200896 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200897 return 0;
898
899err_munmap:
900 for (; i > 0; i--)
901 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
Lars-Peter Clausen55526432017-11-15 13:24:46 +0100902err_block_free:
Lars-Peter Clausen387c8662016-04-21 15:19:09 +0200903 ioctl_nointr(fd, BLOCK_FREE_IOCTL, 0);
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100904 pdata->allocated_nb_blocks = 0;
Romain Roffé0f737472015-06-30 16:45:54 +0200905err_freemem:
906 free(pdata->addrs);
907 pdata->addrs = NULL;
908 free(pdata->blocks);
909 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200910 return ret;
911}
912
Paul Cercueil92f15c22015-04-20 11:36:51 +0200913static int local_open(const struct iio_device *dev,
914 size_t samples_count, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100915{
916 unsigned int i;
917 int ret;
918 char buf[1024];
919 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200920
Romain Roffé6ce74a22015-06-30 11:45:11 +0200921 if (pdata->fd != -1)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100922 return -EBUSY;
923
Paul Cercueilcecda352014-05-06 18:14:29 +0200924 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200925 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100926 return ret;
927
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100928 iio_snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200929 ret = local_write_dev_attr(dev, "buffer/length",
930 buf, strlen(buf) + 1, false);
931 if (ret < 0)
932 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200933
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200934 pdata->cancel_fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
935 if (pdata->cancel_fd == -1)
936 return -errno;
937
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100938 iio_snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +0200939 pdata->fd = open(buf, O_RDWR | O_CLOEXEC | O_NONBLOCK);
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +0200940 if (pdata->fd == -1) {
941 ret = -errno;
942 goto err_close_cancel_fd;
943 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100944
Paul Cercueil11334342015-06-23 16:55:35 +0200945 /* Disable channels */
946 for (i = 0; i < dev->nb_channels; i++) {
947 struct iio_channel *chn = dev->channels[i];
948 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
Lars-Peter Clausen1302f962017-08-10 09:52:58 +0200949 ret = channel_write_state(chn, false);
Paul Cercueil11334342015-06-23 16:55:35 +0200950 if (ret < 0)
951 goto err_close;
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100952 }
Paul Cercueil11334342015-06-23 16:55:35 +0200953 }
954 /* Enable channels */
955 for (i = 0; i < dev->nb_channels; i++) {
956 struct iio_channel *chn = dev->channels[i];
957 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
Lars-Peter Clausen1302f962017-08-10 09:52:58 +0200958 ret = channel_write_state(chn, true);
Paul Cercueil11334342015-06-23 16:55:35 +0200959 if (ret < 0)
960 goto err_close;
Paul Cercueile1311222014-03-12 15:46:16 +0100961 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100962 }
963
Paul Cercueil71694c72014-05-22 14:02:13 +0200964 pdata->cyclic = cyclic;
965 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200966 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200967 pdata->samples_count = samples_count;
Lars-Peter Clausen55526432017-11-15 13:24:46 +0100968
969 ret = enable_high_speed(dev);
970 if (ret < 0 && ret != -ENOSYS)
971 goto err_close;
972
973 pdata->is_high_speed = !ret;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200974
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200975 if (!pdata->is_high_speed) {
Lars-Peter Clausen23605a32017-11-15 13:23:54 +0100976 unsigned long size = samples_count * pdata->max_nb_blocks;
Paul Cercueil032a5652014-05-12 17:11:19 +0200977 WARNING("High-speed mode not enabled\n");
Paul Cercueiled621ee2015-06-24 10:50:21 +0200978
Lars-Peter Clausen23804792016-04-20 18:17:56 +0200979 /* Cyclic mode is only supported in high-speed mode */
Lars-Peter Clausen3e8774c2016-09-21 16:49:32 +0200980 if (cyclic) {
981 ret = -EPERM;
982 goto err_close;
983 }
Lars-Peter Clausen23804792016-04-20 18:17:56 +0200984
Paul Cercueiled621ee2015-06-24 10:50:21 +0200985 /* Increase the size of the kernel buffer, when using the
986 * low-speed interface. This avoids losing samples when
987 * refilling the iio_buffer. */
Paul Cercueil9c9a5562017-01-24 10:48:31 +0100988 iio_snprintf(buf, sizeof(buf), "%lu", size);
Paul Cercueiled621ee2015-06-24 10:50:21 +0200989 ret = local_write_dev_attr(dev, "buffer/length",
990 buf, strlen(buf) + 1, false);
991 if (ret < 0)
992 goto err_close;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200993 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100994
Lars-Peter Clausen53d6d452016-04-20 17:46:11 +0200995 ret = local_enable_buffer(dev);
996 if (ret < 0)
997 goto err_close;
998
Paul Cercueil45c575d2014-03-20 15:14:01 +0100999 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +01001000err_close:
Romain Roffé6ce74a22015-06-30 11:45:11 +02001001 close(pdata->fd);
1002 pdata->fd = -1;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001003err_close_cancel_fd:
1004 close(pdata->cancel_fd);
1005 pdata->cancel_fd = -1;
Paul Cercueile1311222014-03-12 15:46:16 +01001006 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +01001007}
1008
1009static int local_close(const struct iio_device *dev)
1010{
1011 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueil270f3042017-04-11 17:28:59 +02001012 unsigned int i;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +01001013 int ret;
1014
Paul Cercueilb6a40c22015-07-02 11:12:16 +02001015 if (pdata->fd == -1)
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +01001016 return -EBADF;
1017
Paul Cercueil92f46df2014-04-28 13:17:53 +02001018 if (pdata->is_high_speed) {
1019 unsigned int i;
Lars-Peter Clausen23605a32017-11-15 13:23:54 +01001020 for (i = 0; i < pdata->allocated_nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +02001021 munmap(pdata->addrs[i], pdata->blocks[i].size);
Lars-Peter Clausen387c8662016-04-21 15:19:09 +02001022 ioctl_nointr(pdata->fd, BLOCK_FREE_IOCTL, 0);
Lars-Peter Clausen23605a32017-11-15 13:23:54 +01001023 pdata->allocated_nb_blocks = 0;
Romain Roffé0f737472015-06-30 16:45:54 +02001024 free(pdata->addrs);
1025 pdata->addrs = NULL;
1026 free(pdata->blocks);
1027 pdata->blocks = NULL;
Paul Cercueil92f46df2014-04-28 13:17:53 +02001028 }
1029
Romain Roffé6ce74a22015-06-30 11:45:11 +02001030 ret = close(pdata->fd);
Paul Cercueil8a7975e2014-03-12 12:53:43 +01001031 if (ret)
1032 return ret;
1033
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001034 close(pdata->cancel_fd);
1035
Romain Roffé6ce74a22015-06-30 11:45:11 +02001036 pdata->fd = -1;
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001037 pdata->cancel_fd = -1;
1038
Paul Cercueil71694c72014-05-22 14:02:13 +02001039 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueil270f3042017-04-11 17:28:59 +02001040
1041 for (i = 0; i < dev->nb_channels; i++) {
1042 struct iio_channel *chn = dev->channels[i];
1043
Lars-Peter Clausen1302f962017-08-10 09:52:58 +02001044 if (chn->pdata->enable_fn)
1045 channel_write_state(chn, false);
Paul Cercueil270f3042017-04-11 17:28:59 +02001046 }
1047
Paul Cercueil71694c72014-05-22 14:02:13 +02001048 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +01001049}
1050
Romain Roffé87897862015-06-30 13:34:08 +02001051static int local_get_fd(const struct iio_device *dev)
1052{
Paul Cercueil2cdc81b2015-07-02 11:13:23 +02001053 if (dev->pdata->fd == -1)
1054 return -EBADF;
1055 else
1056 return dev->pdata->fd;
Romain Roffé87897862015-06-30 13:34:08 +02001057}
1058
Romain Roffécead1da2015-06-30 13:35:51 +02001059static int local_set_blocking_mode(const struct iio_device *dev, bool blocking)
1060{
Romain Roffécead1da2015-06-30 13:35:51 +02001061 if (dev->pdata->fd == -1)
1062 return -EBADF;
1063
1064 if (dev->pdata->cyclic)
1065 return -EPERM;
1066
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +02001067 dev->pdata->blocking = blocking;
Romain Roffécead1da2015-06-30 13:35:51 +02001068
Lars-Peter Clausen6cc2aff2016-04-22 10:24:15 +02001069 return 0;
Romain Roffécead1da2015-06-30 13:35:51 +02001070}
1071
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001072static int local_get_trigger(const struct iio_device *dev,
1073 const struct iio_device **trigger)
1074{
1075 char buf[1024];
1076 unsigned int i;
1077 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +02001078 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +02001079 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001080 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001081 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +02001082 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001083
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +02001084 if (buf[0] == '\0') {
1085 *trigger = NULL;
1086 return 0;
1087 }
1088
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001089 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +02001090 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001091 const struct iio_device *cur = dev->ctx->devices[i];
1092 if (cur->name && !strcmp(cur->name, buf)) {
1093 *trigger = cur;
1094 return 0;
1095 }
1096 }
1097 return -ENXIO;
1098}
1099
1100static int local_set_trigger(const struct iio_device *dev,
1101 const struct iio_device *trigger)
1102{
1103 ssize_t nb;
1104 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +02001105 nb = local_write_dev_attr(dev, "trigger/current_trigger",
1106 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001107 if (nb < 0)
1108 return (int) nb;
1109 else
1110 return 0;
1111}
1112
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001113static bool is_channel(const char *attr, bool strict)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001114{
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001115 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +01001116 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
1117 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001118 if (!strncmp(attr, "in_", 3))
1119 ptr = strchr(attr + 3, '_');
1120 else if (!strncmp(attr, "out_", 4))
1121 ptr = strchr(attr + 4, '_');
1122 if (!ptr)
1123 return false;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001124 if (!strict)
1125 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001126 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
1127 return true;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001128
Lars-Peter Clausenca20c242018-01-24 11:04:10 +01001129 if (find_channel_modifier(ptr + 1, NULL) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001130 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001131 return false;
1132}
1133
1134static char * get_channel_id(const char *attr)
1135{
Lars-Peter Clausenca20c242018-01-24 11:04:10 +01001136 char *res, *ptr;
1137 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001138
1139 attr = strchr(attr, '_') + 1;
Lars-Peter Clausenca20c242018-01-24 11:04:10 +01001140 ptr = strchr(attr, '_');
1141 if (find_channel_modifier(ptr + 1, &len) != IIO_NO_MOD)
1142 ptr += len + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001143
1144 res = malloc(ptr - attr + 1);
1145 if (!res)
1146 return NULL;
1147
1148 memcpy(res, attr, ptr - attr);
1149 res[ptr - attr] = 0;
1150 return res;
1151}
1152
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001153static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001154{
1155 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001156 size_t len;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +02001157
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001158 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausenca20c242018-01-24 11:04:10 +01001159 if (find_channel_modifier(ptr, &len) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001160 ptr += len + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +02001161
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001162 if (chn->name) {
1163 size_t len = strlen(chn->name);
Robin Getz4c8043f2018-10-24 12:59:06 +00001164 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001165 ptr += len + 1;
1166 }
1167
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001168 return iio_strdup(ptr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001169}
1170
1171static int read_device_name(struct iio_device *dev)
1172{
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001173 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +02001174 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +01001175 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001176 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +01001177 else if (ret == 0)
1178 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001179
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001180 dev->name = iio_strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001181 if (!dev->name)
1182 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +01001183 else
1184 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001185}
1186
1187static int add_attr_to_device(struct iio_device *dev, const char *attr)
1188{
Paul Cercueilbb618272014-02-20 11:35:52 +01001189 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001190 unsigned int i;
1191
1192 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
1193 if (!strcmp(device_attrs_blacklist[i], attr))
1194 return 0;
1195
1196 if (!strcmp(attr, "name"))
1197 return read_device_name(dev);
1198
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001199 name = iio_strdup(attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001200 if (!name)
1201 return -ENOMEM;
1202
1203 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
1204 if (!attrs) {
1205 free(name);
1206 return -ENOMEM;
1207 }
1208
1209 attrs[dev->nb_attrs++] = name;
1210 dev->attrs = attrs;
1211 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
1212 return 0;
1213}
1214
Paul Cercueila1a34c62016-08-09 12:53:39 +02001215static int handle_protected_scan_element_attr(struct iio_channel *chn,
1216 const char *name, const char *path)
1217{
1218 struct iio_device *dev = chn->dev;
1219 char buf[1024];
1220 int ret;
1221
1222 if (!strcmp(name, "index")) {
1223 ret = local_read_dev_attr(dev, path, buf, sizeof(buf), false);
1224 if (ret > 0)
1225 chn->index = atol(buf);
1226
1227 } else if (!strcmp(name, "type")) {
1228 ret = local_read_dev_attr(dev, path, buf, sizeof(buf), false);
1229 if (ret > 0) {
1230 char endian, sign;
1231
Lucas Magasweran77fe2912016-08-29 13:47:29 -07001232 if (strchr(buf, 'X')) {
1233 sscanf(buf, "%ce:%c%u/%uX%u>>%u", &endian, &sign,
1234 &chn->format.bits, &chn->format.length,
1235 &chn->format.repeat, &chn->format.shift);
1236 } else {
1237 chn->format.repeat = 1;
1238 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001239 &chn->format.bits, &chn->format.length,
1240 &chn->format.shift);
Lucas Magasweran77fe2912016-08-29 13:47:29 -07001241 }
Paul Cercueila1a34c62016-08-09 12:53:39 +02001242 chn->format.is_signed = (sign == 's' || sign == 'S');
1243 chn->format.is_fully_defined =
1244 (sign == 'S' || sign == 'U'||
1245 chn->format.bits == chn->format.length);
1246 chn->format.is_be = endian == 'b';
1247 }
1248
1249 } else if (!strcmp(name, "en")) {
1250 if (chn->pdata->enable_fn) {
1251 ERROR("Libiio bug: \"en\" attribute already parsed for channel %s!\n",
1252 chn->id);
1253 return -EINVAL;
1254 }
1255
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001256 chn->pdata->enable_fn = iio_strdup(path);
Paul Cercueila1a34c62016-08-09 12:53:39 +02001257 if (!chn->pdata->enable_fn)
1258 return -ENOMEM;
1259
1260 } else {
1261 return -EINVAL;
1262 }
1263
1264 return 0;
1265}
1266
Paul Cercueil54e96cc2016-12-19 12:27:25 +01001267static int handle_scan_elements(struct iio_channel *chn)
1268{
1269 struct iio_channel_pdata *pdata = chn->pdata;
1270 unsigned int i;
1271
1272 for (i = 0; i < pdata->nb_protected_attrs; i++) {
1273 int ret = handle_protected_scan_element_attr(chn,
1274 pdata->protected_attrs[i].name,
1275 pdata->protected_attrs[i].filename);
1276 if (ret < 0)
1277 return ret;
1278 }
1279
1280 return 0;
1281}
1282
1283static int add_protected_attr(struct iio_channel *chn, char *name, char *fn)
1284{
1285 struct iio_channel_pdata *pdata = chn->pdata;
1286 struct iio_channel_attr *attrs;
1287
1288 attrs = realloc(pdata->protected_attrs,
1289 (1 + pdata->nb_protected_attrs) * sizeof(*attrs));
1290 if (!attrs)
1291 return -ENOMEM;
1292
1293 attrs[pdata->nb_protected_attrs].name = name;
1294 attrs[pdata->nb_protected_attrs++].filename = fn;
1295 pdata->protected_attrs = attrs;
1296
1297 DEBUG("Add protected attr \'%s\' to channel \'%s\'\n", name, chn->id);
1298 return 0;
1299}
1300
1301static void free_protected_attrs(struct iio_channel *chn)
1302{
1303 struct iio_channel_pdata *pdata = chn->pdata;
1304 unsigned int i;
1305
1306 for (i = 0; i < pdata->nb_protected_attrs; i++) {
1307 free(pdata->protected_attrs[i].name);
1308 free(pdata->protected_attrs[i].filename);
1309 }
1310
1311 free(pdata->protected_attrs);
1312 pdata->nb_protected_attrs = 0;
Gwendal Grignou8a5a00b2017-05-08 10:03:40 -07001313 pdata->protected_attrs = NULL;
Paul Cercueil54e96cc2016-12-19 12:27:25 +01001314}
1315
Paul Cercueile3fbd952014-03-11 16:58:33 +01001316static int add_attr_to_channel(struct iio_channel *chn,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001317 const char *attr, const char *path, bool is_scan_element)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001318{
Paul Cercueilb34e0222014-05-05 15:32:38 +02001319 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001320 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001321 if (!name)
1322 return -ENOMEM;
1323
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001324 fn = iio_strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +01001325 if (!fn)
1326 goto err_free_name;
1327
Paul Cercueil54e96cc2016-12-19 12:27:25 +01001328 if (is_scan_element) {
1329 int ret = add_protected_attr(chn, name, fn);
1330
1331 if (ret < 0)
1332 goto err_free_fn;
1333
1334 return 0;
1335 }
1336
Paul Cercueilb34e0222014-05-05 15:32:38 +02001337 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
1338 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +01001339 if (!attrs)
1340 goto err_free_fn;
1341
Paul Cercueil42d12352014-05-05 16:11:58 +02001342 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +02001343 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001344 chn->attrs = attrs;
1345 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
1346 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +01001347
Paul Cercueil167d3112014-02-18 12:23:53 +01001348err_free_fn:
1349 free(fn);
1350err_free_name:
1351 free(name);
1352 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001353}
1354
1355static int add_channel_to_device(struct iio_device *dev,
1356 struct iio_channel *chn)
1357{
1358 struct iio_channel **channels = realloc(dev->channels,
1359 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
1360 if (!channels)
1361 return -ENOMEM;
1362
1363 channels[dev->nb_channels++] = chn;
1364 dev->channels = channels;
Robin Getz57295ce2018-05-24 21:45:08 +00001365 DEBUG("Added %s channel \'%s\' to device \'%s\'\n",
1366 chn->is_output ? "output" : "input", chn->id, dev->id);
1367
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001368 return 0;
1369}
1370
1371static int add_device_to_context(struct iio_context *ctx,
1372 struct iio_device *dev)
1373{
1374 struct iio_device **devices = realloc(ctx->devices,
1375 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
1376 if (!devices)
1377 return -ENOMEM;
1378
1379 devices[ctx->nb_devices++] = dev;
1380 ctx->devices = devices;
1381 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
1382 return 0;
1383}
1384
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001385static struct iio_channel *create_channel(struct iio_device *dev,
Paul Cercueila1a34c62016-08-09 12:53:39 +02001386 char *id, const char *attr, const char *path,
1387 bool is_scan_element)
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001388{
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001389 struct iio_channel *chn = zalloc(sizeof(*chn));
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001390 if (!chn)
1391 return NULL;
1392
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001393 chn->pdata = zalloc(sizeof(*chn->pdata));
1394 if (!chn->pdata)
1395 goto err_free_chn;
1396
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001397 if (!strncmp(attr, "out_", 4))
1398 chn->is_output = true;
1399 else if (strncmp(attr, "in_", 3))
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001400 goto err_free_chn_pdata;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001401
1402 chn->dev = dev;
1403 chn->id = id;
Paul Cercueila1a34c62016-08-09 12:53:39 +02001404 chn->is_scan_element = is_scan_element;
1405 chn->index = -ENOENT;
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001406
Paul Cercueila1a34c62016-08-09 12:53:39 +02001407 if (!add_attr_to_channel(chn, attr, path, is_scan_element))
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001408 return chn;
1409
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001410err_free_chn_pdata:
1411 free(chn->pdata->enable_fn);
1412 free(chn->pdata);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001413err_free_chn:
1414 free(chn);
1415 return NULL;
1416}
1417
1418static int add_channel(struct iio_device *dev, const char *name,
1419 const char *path, bool dir_is_scan_elements)
1420{
1421 struct iio_channel *chn;
1422 char *channel_id;
1423 unsigned int i;
1424 int ret;
1425
1426 channel_id = get_channel_id(name);
1427 if (!channel_id)
1428 return -ENOMEM;
1429
1430 for (i = 0; i < dev->nb_channels; i++) {
1431 chn = dev->channels[i];
1432 if (!strcmp(chn->id, channel_id)
1433 && chn->is_output == (name[0] == 'o')) {
1434 free(channel_id);
Paul Cercueila1a34c62016-08-09 12:53:39 +02001435 ret = add_attr_to_channel(chn, name, path,
1436 dir_is_scan_elements);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001437 chn->is_scan_element = dir_is_scan_elements && !ret;
1438 return ret;
1439 }
1440 }
1441
Paul Cercueila1a34c62016-08-09 12:53:39 +02001442 chn = create_channel(dev, channel_id, name, path, dir_is_scan_elements);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001443 if (!chn) {
1444 free(channel_id);
1445 return -ENXIO;
1446 }
Lars-Peter Clausenc6f85922016-04-20 15:03:49 +02001447
1448 iio_channel_init_finalize(chn);
1449
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001450 ret = add_channel_to_device(dev, chn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001451 if (ret) {
1452 free(chn->pdata->enable_fn);
1453 free(chn->pdata);
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001454 free_channel(chn);
Paul Cercueil3f9dcb02016-08-09 17:16:25 +02001455 }
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001456 return ret;
1457}
1458
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001459/*
1460 * Possible return values:
1461 * 0 = Attribute should not be moved to the channel
1462 * 1 = Attribute should be moved to the channel and it is a shared attribute
1463 * 2 = Attribute should be moved to the channel and it is a private attribute
1464 */
1465static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001466{
Lars-Peter Clausen8ba0d5b2016-02-17 11:30:23 +01001467 unsigned int len;
fpagliughi94ee2182020-01-25 16:32:56 -05001468 char *ptr, *dashptr;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001469
Paul Cercueil35a01312014-02-20 10:56:57 +01001470 if (!chn->is_output && !strncmp(attr, "in_", 3))
1471 attr += 3;
1472 else if (chn->is_output && !strncmp(attr, "out_", 4))
1473 attr += 4;
1474 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001475 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001476
Lars-Peter Clausenca20c242018-01-24 11:04:10 +01001477 ptr = strchr(attr, '_');
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001478 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001479 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001480
1481 len = ptr - attr;
1482
fpagliughi6af74f22020-01-31 09:04:48 -05001483 // Check for matching global differential attr, like "voltage-voltage"
fpagliughi94ee2182020-01-25 16:32:56 -05001484 dashptr = strchr(attr, '-');
1485 if (dashptr && dashptr > attr && dashptr < ptr) {
fpagliughief761f22020-02-03 09:04:56 -05001486 unsigned int len1 = dashptr - attr;
1487 unsigned int len2 = ptr - dashptr - 1;
fpagliughi6af74f22020-01-31 09:04:48 -05001488 const char* iddashptr = strchr(chn->id, '-');
fpagliughief761f22020-02-03 09:04:56 -05001489 if (iddashptr && strlen(iddashptr + 1) > len2 &&
fpagliughi6af74f22020-01-31 09:04:48 -05001490 iddashptr - chn->id > len1 &&
1491 chn->id[len1] >= '0' && chn->id[len1] <= '9' &&
fpagliughi94ee2182020-01-25 16:32:56 -05001492 !strncmp(chn->id, attr, len1) &&
fpagliughief761f22020-02-03 09:04:56 -05001493 iddashptr[len2 + 1] >= '0' && iddashptr[len2 + 1] <= '9' &&
1494 !strncmp(iddashptr + 1, dashptr + 1, len2))
fpagliughi94ee2182020-01-25 16:32:56 -05001495 return 1;
1496 }
1497
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001498 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001499 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001500
1501 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001502 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1503 if (chn->name) {
1504 size_t name_len = strlen(chn->name);
1505 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1506 attr[len + 1 + name_len] == '_')
1507 return 2;
1508 }
1509 return 1;
1510 } else if (chn->id[len] != '_') {
1511 return 0;
1512 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001513
Lars-Peter Clausenca20c242018-01-24 11:04:10 +01001514 if (find_channel_modifier(chn->id + len + 1, NULL) != IIO_NO_MOD)
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001515 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001516
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001517 return 0;
1518}
1519
1520static int detect_global_attr(struct iio_device *dev, const char *attr,
1521 unsigned int level, bool *match)
1522{
1523 unsigned int i;
1524
1525 *match = false;
1526 for (i = 0; i < dev->nb_channels; i++) {
1527 struct iio_channel *chn = dev->channels[i];
1528 if (is_global_attr(chn, attr) == level) {
1529 int ret;
1530 *match = true;
Paul Cercueila1a34c62016-08-09 12:53:39 +02001531 ret = add_attr_to_channel(chn, attr, attr, false);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001532 if (ret)
1533 return ret;
1534 }
1535 }
1536
1537 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001538}
1539
1540static int detect_and_move_global_attrs(struct iio_device *dev)
1541{
1542 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001543 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001544
1545 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001546 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001547 bool match;
1548 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001549
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001550 ret = detect_global_attr(dev, attr, 2, &match);
1551 if (ret)
1552 return ret;
1553
1554 if (!match) {
1555 ret = detect_global_attr(dev, attr, 1, &match);
1556 if (ret)
1557 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001558 }
1559
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001560 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001561 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001562 dev->attrs[i] = NULL;
1563 }
1564 }
1565
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001566 /* Find channels without an index */
1567 for (i = 0; i < dev->nb_attrs; i++) {
1568 const char *attr = dev->attrs[i];
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001569 int ret;
1570
1571 if (!dev->attrs[i])
1572 continue;
1573
1574 if (is_channel(attr, false)) {
1575 ret = add_channel(dev, attr, attr, false);
1576 if (ret)
1577 return ret;
1578
1579 free(dev->attrs[i]);
1580 dev->attrs[i] = NULL;
1581 }
1582 }
1583
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001584 for (i = 0; i < dev->nb_attrs; i++) {
1585 if (dev->attrs[i])
1586 *ptr++ = dev->attrs[i];
1587 }
1588
1589 dev->nb_attrs = ptr - dev->attrs;
Lars-Peter Clausene8a2bb32016-04-12 18:43:31 +02001590 if (!dev->nb_attrs) {
1591 free(dev->attrs);
1592 dev->attrs = NULL;
1593 }
1594
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001595 return 0;
1596}
1597
Matt Fornero7f9598f2017-11-30 14:07:52 -05001598static int add_buffer_attr(void *d, const char *path)
1599{
1600 struct iio_device *dev = (struct iio_device *) d;
1601 const char *name = strrchr(path, '/') + 1;
1602 char **attrs, *attr;
1603 int i;
1604
1605 for (i = 0; i < ARRAY_SIZE(buffer_attrs_reserved); i++)
1606 if (!strcmp(buffer_attrs_reserved[i], name))
1607 return 0;
1608
1609 attr = iio_strdup(name);
1610 if (!attr)
1611 return -ENOMEM;
1612
1613 attrs = realloc(dev->buffer_attrs, (1 + dev->nb_buffer_attrs) * sizeof(char *));
1614 if (!attrs) {
1615 free(attr);
1616 return -ENOMEM;
1617 }
1618
1619 attrs[dev->nb_buffer_attrs++] = attr;
1620 dev->buffer_attrs = attrs;
1621 DEBUG("Added buffer attr \'%s\' to device \'%s\'\n", attr, dev->id);
1622 return 0;
1623}
1624
Paul Cercueile3fbd952014-03-11 16:58:33 +01001625static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001626 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001627{
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001628 char buf[1024];
Paul Cercueil1be57832014-03-11 16:27:16 +01001629 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001630
1631 if (dir_is_scan_elements) {
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001632 iio_snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001633 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001634 } else {
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001635 if (!is_channel(name, true))
1636 return add_attr_to_device(dev, name);
Paul Cercueila91358e2014-04-24 16:40:19 +02001637 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001638 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001639
Lars-Peter Clausend9806c22016-01-26 16:35:42 +01001640 return add_channel(dev, name, path, dir_is_scan_elements);
Paul Cercueil1be57832014-03-11 16:27:16 +01001641}
1642
Paul Cercueile3fbd952014-03-11 16:58:33 +01001643static int add_attr_or_channel(void *d, const char *path)
1644{
Paul Cercueila91358e2014-04-24 16:40:19 +02001645 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001646}
1647
1648static int add_scan_element(void *d, const char *path)
1649{
Paul Cercueila91358e2014-04-24 16:40:19 +02001650 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001651}
1652
Paul Cercueil1be57832014-03-11 16:27:16 +01001653static int foreach_in_dir(void *d, const char *path, bool is_dir,
1654 int (*callback)(void *, const char *))
1655{
Paul Cercueil883204f2016-11-17 12:35:28 +01001656 struct dirent *entry;
1657 DIR *dir;
1658 int ret = 0;
1659
1660 dir = opendir(path);
Paul Cercueil1be57832014-03-11 16:27:16 +01001661 if (!dir)
1662 return -errno;
1663
Paul Cercueil1be57832014-03-11 16:27:16 +01001664 while (true) {
1665 struct stat st;
1666 char buf[1024];
Paul Cercueil883204f2016-11-17 12:35:28 +01001667
1668 errno = 0;
1669 entry = readdir(dir);
1670 if (!entry) {
1671 if (!errno)
1672 break;
1673
1674 ret = -errno;
1675 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001676 ERROR("Unable to open directory %s: %s\n", path, buf);
Paul Cercueil883204f2016-11-17 12:35:28 +01001677 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001678 }
Paul Cercueil1be57832014-03-11 16:27:16 +01001679
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001680 iio_snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
Paul Cercueil1be57832014-03-11 16:27:16 +01001681 if (stat(buf, &st) < 0) {
1682 ret = -errno;
Paul Cercueil87b988f2015-05-22 10:57:32 +02001683 iio_strerror(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001684 ERROR("Unable to stat file: %s\n", buf);
Paul Cercueil883204f2016-11-17 12:35:28 +01001685 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001686 }
1687
1688 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1689 ret = callback(d, buf);
1690 else if (!is_dir && S_ISREG(st.st_mode))
1691 ret = callback(d, buf);
1692 else
1693 continue;
1694
Paul Cercueil883204f2016-11-17 12:35:28 +01001695 if (ret < 0)
1696 goto out_close_dir;
Paul Cercueil1be57832014-03-11 16:27:16 +01001697 }
1698
Paul Cercueil883204f2016-11-17 12:35:28 +01001699out_close_dir:
Paul Cercueil1be57832014-03-11 16:27:16 +01001700 closedir(dir);
Paul Cercueil883204f2016-11-17 12:35:28 +01001701 return ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001702}
1703
Paul Cercueile3fbd952014-03-11 16:58:33 +01001704static int add_scan_elements(struct iio_device *dev, const char *devpath)
1705{
1706 struct stat st;
1707 char buf[1024];
Paul Cercueil9c9a5562017-01-24 10:48:31 +01001708
1709 iio_snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001710
1711 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1712 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1713 if (ret < 0)
1714 return ret;
1715 }
1716
1717 return 0;
1718}
1719
Matt Fornero7f9598f2017-11-30 14:07:52 -05001720static int add_buffer_attributes(struct iio_device *dev, const char *devpath)
1721{
1722 struct stat st;
1723 char buf[1024];
1724
1725 iio_snprintf(buf, sizeof(buf), "%s/buffer", devpath);
1726
1727 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1728 int ret = foreach_in_dir(dev, buf, false, add_buffer_attr);
1729 if (ret < 0)
1730 return ret;
Robin Getz57295ce2018-05-24 21:45:08 +00001731
1732 qsort(dev->buffer_attrs, dev->nb_buffer_attrs, sizeof(char *),
Robin Getzb8634362018-10-24 12:39:11 +00001733 iio_buffer_attr_compare);
Matt Fornero7f9598f2017-11-30 14:07:52 -05001734 }
1735
1736 return 0;
1737}
1738
Paul Cercueil1be57832014-03-11 16:27:16 +01001739static int create_device(void *d, const char *path)
1740{
Paul Cercueilff778232014-03-24 14:23:08 +01001741 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001742 unsigned int i;
1743 int ret;
1744 struct iio_context *ctx = d;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001745 struct iio_device *dev = zalloc(sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001746 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001747 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001748
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01001749 dev->pdata = zalloc(sizeof(*dev->pdata));
Paul Cercueileaab6582014-02-21 09:35:59 +01001750 if (!dev->pdata) {
1751 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001752 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001753 }
1754
Romain Roffé6ce74a22015-06-30 11:45:11 +02001755 dev->pdata->fd = -1;
Romain Roffécead1da2015-06-30 13:35:51 +02001756 dev->pdata->blocking = true;
Lars-Peter Clausen23605a32017-11-15 13:23:54 +01001757 dev->pdata->max_nb_blocks = NB_BLOCKS;
Romain Roffé6ce74a22015-06-30 11:45:11 +02001758
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001759 dev->ctx = ctx;
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001760 dev->id = iio_strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001761 if (!dev->id) {
Romain Roffé0f737472015-06-30 16:45:54 +02001762 local_free_pdata(dev);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001763 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001764 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001765 }
1766
Paul Cercueil1be57832014-03-11 16:27:16 +01001767 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001768 if (ret < 0)
1769 goto err_free_device;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001770
Matt Fornero7f9598f2017-11-30 14:07:52 -05001771 ret = add_buffer_attributes(dev, path);
1772 if (ret < 0)
1773 goto err_free_device;
Robin Getz4c8043f2018-10-24 12:59:06 +00001774
Michael Hennerichebe49662014-11-07 10:32:44 +01001775 ret = add_scan_elements(dev, path);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001776 if (ret < 0)
Paul Cercueil54e96cc2016-12-19 12:27:25 +01001777 goto err_free_scan_elements;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001778
Paul Cercueil54e96cc2016-12-19 12:27:25 +01001779 for (i = 0; i < dev->nb_channels; i++) {
1780 struct iio_channel *chn = dev->channels[i];
1781
1782 set_channel_name(chn);
1783 ret = handle_scan_elements(chn);
1784 free_protected_attrs(chn);
Enrico Granata8539d5d2019-05-06 11:05:23 -07001785 if (ret < 0) {
1786 if (dev->name &&
1787 !strcmp("cros-ec-ring", dev->name)) {
1788 DEBUG("ignoring cros-ec-ring\n");
1789
1790 /* pretend the operation completed successfully
1791 * even though we can't process the attributes
1792 * of the sensor ring */
1793 ret = 0;
1794 goto err_free_scan_elements;
1795 }
1796 }
Paul Cercueil54e96cc2016-12-19 12:27:25 +01001797 }
Paul Cercueilbab69a92015-07-03 11:24:17 +02001798
Michael Hennerichebe49662014-11-07 10:32:44 +01001799 ret = detect_and_move_global_attrs(dev);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001800 if (ret < 0)
1801 goto err_free_device;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001802
Robin Getzb26e7c32018-11-05 03:13:05 +00001803 /* sorting is done after global attrs are added */
1804 for (i = 0; i < dev->nb_channels; i++) {
1805 struct iio_channel *chn = dev->channels[i];
1806 qsort(chn->attrs, chn->nb_attrs, sizeof(struct iio_channel_attr),
1807 iio_channel_attr_compare);
1808 }
Robin Getz4c8043f2018-10-24 12:59:06 +00001809 qsort(dev->attrs, dev->nb_attrs, sizeof(char *),
Robin Getzb8634362018-10-24 12:39:11 +00001810 iio_device_attr_compare);
Robin Getz57295ce2018-05-24 21:45:08 +00001811
Paul Cercueilff778232014-03-24 14:23:08 +01001812 dev->words = (dev->nb_channels + 31) / 32;
1813 if (dev->words) {
1814 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001815 if (!mask) {
Paul Cercueil290e0e02016-08-09 15:54:44 +02001816 ret = -ENOMEM;
1817 goto err_free_device;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001818 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001819 }
1820
Paul Cercueilff778232014-03-24 14:23:08 +01001821 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001822
Paul Cercueil1be57832014-03-11 16:27:16 +01001823 ret = add_device_to_context(ctx, dev);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001824 if (!ret)
1825 return 0;
1826
Paul Cercueil54e96cc2016-12-19 12:27:25 +01001827err_free_scan_elements:
1828 for (i = 0; i < dev->nb_channels; i++)
1829 free_protected_attrs(dev->channels[i]);
Paul Cercueil290e0e02016-08-09 15:54:44 +02001830err_free_device:
1831 local_free_pdata(dev);
1832 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001833 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001834}
1835
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001836static int add_debug_attr(void *d, const char *path)
1837{
1838 struct iio_device *dev = d;
1839 const char *attr = strrchr(path, '/') + 1;
Paul Cercueilcaf0e712016-08-25 17:27:02 +02001840 char **attrs, *name = iio_strdup(attr);
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001841 if (!name)
1842 return -ENOMEM;
1843
1844 attrs = realloc(dev->debug_attrs,
1845 (1 + dev->nb_debug_attrs) * sizeof(char *));
1846 if (!attrs) {
1847 free(name);
1848 return -ENOMEM;
1849 }
1850
1851 attrs[dev->nb_debug_attrs++] = name;
1852 dev->debug_attrs = attrs;
1853 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1854 return 0;
1855}
1856
1857static int add_debug(void *d, const char *path)
1858{
1859 struct iio_context *ctx = d;
1860 const char *name = strrchr(path, '/') + 1;
1861 struct iio_device *dev = iio_context_find_device(ctx, name);
1862 if (!dev)
1863 return -ENODEV;
1864 else
1865 return foreach_in_dir(dev, path, false, add_debug_attr);
1866}
1867
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001868static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1869{
Paul Cercueil00558f12016-04-12 14:40:40 +02001870 ctx->pdata->rw_timeout_ms = timeout;
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001871 return 0;
1872}
1873
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001874static void local_cancel(const struct iio_device *dev)
1875{
1876 struct iio_device_pdata *pdata = dev->pdata;
1877 uint64_t event = 1;
1878 int ret;
1879
1880 ret = write(pdata->cancel_fd, &event, sizeof(event));
1881 if (ret == -1) {
1882 /* If this happens something went very seriously wrong */
1883 char err_str[1024];
1884 iio_strerror(errno, err_str, sizeof(err_str));
1885 ERROR("Unable to signal cancellation event: %s\n", err_str);
1886 }
1887}
1888
Paul Cercueil0865e802014-10-28 14:35:19 +01001889static struct iio_context * local_clone(
1890 const struct iio_context *ctx __attribute__((unused)))
1891{
Paul Cercueil63e52182014-12-11 12:52:48 +01001892 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001893}
1894
Lars-Peter Clausen09a59d72016-02-03 15:27:04 +01001895static const struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001896 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001897 .open = local_open,
1898 .close = local_close,
Romain Roffé87897862015-06-30 13:34:08 +02001899 .get_fd = local_get_fd,
Romain Roffécead1da2015-06-30 13:35:51 +02001900 .set_blocking_mode = local_set_blocking_mode,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001901 .read = local_read,
1902 .write = local_write,
Romain Roffé0f737472015-06-30 16:45:54 +02001903 .set_kernel_buffers_count = local_set_kernel_buffers_count,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001904 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001905 .read_device_attr = local_read_dev_attr,
1906 .write_device_attr = local_write_dev_attr,
1907 .read_channel_attr = local_read_chn_attr,
1908 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001909 .get_trigger = local_get_trigger,
1910 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001911 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001912 .set_timeout = local_set_timeout,
Lars-Peter Clausenf4b57c22016-04-21 16:46:53 +02001913 .cancel = local_cancel,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001914};
1915
Paul Cercueila1a34c62016-08-09 12:53:39 +02001916static void init_data_scale(struct iio_channel *chn)
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001917{
1918 char buf[1024];
1919 ssize_t ret;
1920
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001921 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1922 if (ret < 0) {
1923 chn->format.with_scale = false;
1924 } else {
1925 chn->format.with_scale = true;
1926 chn->format.scale = atof(buf);
1927 }
1928}
1929
1930static void init_scan_elements(struct iio_context *ctx)
1931{
1932 unsigned int i, j;
1933
1934 for (i = 0; i < ctx->nb_devices; i++) {
1935 struct iio_device *dev = ctx->devices[i];
1936
Paul Cercueila1a34c62016-08-09 12:53:39 +02001937 for (j = 0; j < dev->nb_channels; j++)
1938 init_data_scale(dev->channels[j]);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001939 }
1940}
1941
Paul Cercueile6be0702016-11-18 10:57:23 +01001942#ifdef WITH_LOCAL_CONFIG
1943static int populate_context_attrs(struct iio_context *ctx, const char *file)
1944{
1945 struct INI *ini;
1946 int ret;
1947
1948 ini = ini_open(file);
1949 if (!ini) {
1950 /* INI file not present -> not an error */
1951 if (errno == ENOENT)
1952 return 0;
1953 else
1954 return -errno;
1955 }
1956
1957 while (true) {
1958 const char *section;
1959 size_t len;
1960
1961 ret = ini_next_section(ini, &section, &len);
1962 if (ret <= 0)
1963 goto out_close_ini;
1964
1965 if (!strncmp(section, "Context Attributes", len))
1966 break;
1967 }
1968
1969 do {
1970 const char *key, *value;
1971 char *new_key, *new_val;
1972 size_t klen, vlen;
1973
1974 ret = ini_read_pair(ini, &key, &klen, &value, &vlen);
1975 if (ret <= 0)
1976 break;
1977
1978 /* Create a dup of the strings read from the INI, since they are
1979 * not NULL-terminated. */
1980 new_key = strndup(key, klen);
1981 new_val = strndup(value, vlen);
1982
1983 if (!new_key || !new_val)
1984 ret = -ENOMEM;
1985 else
1986 ret = iio_context_add_attr(ctx, new_key, new_val);
1987
1988 free(new_key);
1989 free(new_val);
1990 } while (!ret);
1991
1992out_close_ini:
1993 ini_close(ini);
1994 return ret;
1995}
1996#endif
1997
Paul Cercueil63e52182014-12-11 12:52:48 +01001998struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001999{
Paul Cercueilfd387472015-08-05 10:34:19 +02002000 int ret = -ENOMEM;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01002001 unsigned int len;
2002 struct utsname uts;
Lars-Peter Clausend1be8382016-02-24 11:13:45 +01002003 struct iio_context *ctx = zalloc(sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01002004 if (!ctx)
Paul Cercueilfd387472015-08-05 10:34:19 +02002005 goto err_set_errno;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01002006
Paul Cercueil0b2ce712014-02-17 15:04:18 +01002007 ctx->ops = &local_ops;
2008 ctx->name = "local";
Harvey Yangbc3f48e2019-10-22 11:17:28 +08002009 ctx->client_id = -1;
Paul Cercueil00558f12016-04-12 14:40:40 +02002010
2011 ctx->pdata = zalloc(sizeof(*ctx->pdata));
2012 if (!ctx->pdata) {
2013 free(ctx);
2014 goto err_set_errno;
2015 }
2016
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02002017 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01002018
Paul Cercueilc957d9f2015-01-08 15:05:42 +01002019 uname(&uts);
2020 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
2021 + strlen(uts.version) + strlen(uts.machine);
2022 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
2023 if (!ctx->description) {
Paul Cercueil00558f12016-04-12 14:40:40 +02002024 free(ctx->pdata);
Paul Cercueilc957d9f2015-01-08 15:05:42 +01002025 free(ctx);
Paul Cercueilfd387472015-08-05 10:34:19 +02002026 goto err_set_errno;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01002027 }
2028
Paul Cercueil9c9a5562017-01-24 10:48:31 +01002029 iio_snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
Paul Cercueilc957d9f2015-01-08 15:05:42 +01002030 uts.nodename, uts.release, uts.version, uts.machine);
2031
Paul Cercueil1be57832014-03-11 16:27:16 +01002032 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
Paul Cercueilfd387472015-08-05 10:34:19 +02002033 if (ret < 0)
2034 goto err_context_destroy;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02002035
Robin Getz57295ce2018-05-24 21:45:08 +00002036 qsort(ctx->devices, ctx->nb_devices, sizeof(struct iio_device *),
Robin Getzb8634362018-10-24 12:39:11 +00002037 iio_device_compare);
Robin Getz57295ce2018-05-24 21:45:08 +00002038
Paul Cercueilddaa26a2014-04-14 17:32:18 +02002039 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02002040
Paul Cercueilcac16ac2014-06-11 14:32:17 +02002041 init_scan_elements(ctx);
Paul Cercueile6be0702016-11-18 10:57:23 +01002042
2043#ifdef WITH_LOCAL_CONFIG
2044 ret = populate_context_attrs(ctx, "/etc/libiio.ini");
2045 if (ret < 0)
2046 goto err_context_destroy;
2047#endif
2048
Paul Cercueil267b25a2016-11-24 17:30:58 +01002049 ret = iio_context_add_attr(ctx, "local,kernel", uts.release);
2050 if (ret < 0)
2051 goto err_context_destroy;
2052
Paul Cercueilfd387472015-08-05 10:34:19 +02002053 ret = iio_context_init(ctx);
2054 if (ret < 0)
2055 goto err_context_destroy;
Paul Cercueilae88fde2014-03-12 11:47:10 +01002056
Paul Cercueil0b2ce712014-02-17 15:04:18 +01002057 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01002058
Paul Cercueilfd387472015-08-05 10:34:19 +02002059err_context_destroy:
2060 iio_context_destroy(ctx);
2061err_set_errno:
2062 errno = -ret;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01002063 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01002064}
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02002065
2066static int check_device(void *d, const char *path)
2067{
2068 *(bool *)d = true;
2069 return 0;
2070}
2071
2072int local_context_scan(struct iio_scan_result *scan_result)
2073{
2074 struct iio_context_info **info;
2075 bool exists = false;
Paul Cercueil6303ca22016-11-10 16:55:40 +01002076 char *desc, *uri;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02002077 int ret;
2078
Paul Cercueilea6ab972016-12-21 18:24:03 +01002079 ret = foreach_in_dir(&exists, "/sys/bus/iio", true, check_device);
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02002080 if (ret < 0 || !exists)
2081 return 0;
2082
Paul Cercueil6303ca22016-11-10 16:55:40 +01002083 desc = iio_strdup("Local devices");
2084 if (!desc)
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02002085 return -ENOMEM;
2086
Paul Cercueil6303ca22016-11-10 16:55:40 +01002087 uri = iio_strdup("local:");
2088 if (!uri)
2089 goto err_free_desc;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02002090
Paul Cercueil6303ca22016-11-10 16:55:40 +01002091 info = iio_scan_result_add(scan_result, 1);
2092 if (!info)
2093 goto err_free_uri;
2094
2095 info[0]->description = desc;
2096 info[0]->uri = uri;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02002097 return 0;
Paul Cercueil6303ca22016-11-10 16:55:40 +01002098
2099err_free_uri:
2100 free(uri);
2101err_free_desc:
2102 free(desc);
2103 return -ENOMEM;
Lars-Peter Clausen3db58d62016-04-25 15:00:54 +02002104}