/* * libiio - Library for interfacing industrial I/O (IIO) devices * * Copyright (C) 2014 Analog Devices, Inc. * Author: Paul Cercueil * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * */ #include "debug.h" #include "iio-private.h" #include #include #include #include static char *get_attr_xml(const char *attr, size_t *length, enum iio_attr_type type) { size_t len = sizeof("") + strlen(attr); char *str; switch(type){ case IIO_ATTR_TYPE_DEVICE: break; case IIO_ATTR_TYPE_DEBUG: len += (sizeof("debug-") - 1); break; case IIO_ATTR_TYPE_BUFFER: len += (sizeof("buffer-") - 1); break; default: return NULL; } str = malloc(len); if (!str) return NULL; *length = len - 1; /* Skip the \0 */ switch (type) { case IIO_ATTR_TYPE_DEVICE: iio_snprintf(str, len, "", attr); break; case IIO_ATTR_TYPE_DEBUG: iio_snprintf(str, len, "", attr); break; case IIO_ATTR_TYPE_BUFFER: iio_snprintf(str, len, "", attr); break; } return str; } /* Returns a string containing the XML representation of this device */ char * iio_device_get_xml(const struct iio_device *dev, size_t *length) { size_t len = sizeof("") + strlen(dev->id) + (dev->name ? strlen(dev->name) : 0); char *ptr, *str, **attrs, **channels, **buffer_attrs, **debug_attrs; size_t *attrs_len, *channels_len, *buffer_attrs_len, *debug_attrs_len; unsigned int i, j, k; attrs_len = malloc(dev->nb_attrs * sizeof(*attrs_len)); if (!attrs_len) return NULL; attrs = malloc(dev->nb_attrs * sizeof(*attrs)); if (!attrs) goto err_free_attrs_len; for (i = 0; i < dev->nb_attrs; i++) { char *xml = get_attr_xml(dev->attrs[i], &attrs_len[i], IIO_ATTR_TYPE_DEVICE); if (!xml) goto err_free_attrs; attrs[i] = xml; len += attrs_len[i]; } channels_len = malloc(dev->nb_channels * sizeof(*channels_len)); if (!channels_len) goto err_free_attrs; channels = malloc(dev->nb_channels * sizeof(*channels)); if (!channels) goto err_free_channels_len; for (j = 0; j < dev->nb_channels; j++) { char *xml = iio_channel_get_xml(dev->channels[j], &channels_len[j]); if (!xml) goto err_free_channels; channels[j] = xml; len += channels_len[j]; } buffer_attrs_len = malloc(dev->nb_buffer_attrs * sizeof(*buffer_attrs_len)); if (!buffer_attrs_len) goto err_free_channels; buffer_attrs = malloc(dev->nb_buffer_attrs * sizeof(*buffer_attrs)); if (!buffer_attrs) goto err_free_buffer_attrs_len; for (k = 0; k < dev->nb_buffer_attrs; k++) { char *xml = get_attr_xml(dev->buffer_attrs[k], &buffer_attrs_len[k], IIO_ATTR_TYPE_BUFFER); if (!xml) goto err_free_buffer_attrs; buffer_attrs[k] = xml; len += buffer_attrs_len[k]; } debug_attrs_len = malloc(dev->nb_debug_attrs * sizeof(*debug_attrs_len)); if (!debug_attrs_len) goto err_free_buffer_attrs; debug_attrs = malloc(dev->nb_debug_attrs * sizeof(*debug_attrs)); if (!debug_attrs) goto err_free_debug_attrs_len; for (k = 0; k < dev->nb_debug_attrs; k++) { char *xml = get_attr_xml(dev->debug_attrs[k], &debug_attrs_len[k], IIO_ATTR_TYPE_DEBUG); if (!xml) goto err_free_debug_attrs; debug_attrs[k] = xml; len += debug_attrs_len[k]; } str = malloc(len); if (!str) goto err_free_debug_attrs; iio_snprintf(str, len, "id); ptr = strrchr(str, '\0'); if (dev->name) { sprintf(ptr, " name=\"%s\"", dev->name); ptr = strrchr(ptr, '\0'); } strcpy(ptr, " >"); ptr += 2; for (i = 0; i < dev->nb_channels; i++) { strcpy(ptr, channels[i]); ptr += channels_len[i]; free(channels[i]); } free(channels); free(channels_len); for (i = 0; i < dev->nb_attrs; i++) { strcpy(ptr, attrs[i]); ptr += attrs_len[i]; free(attrs[i]); } free(attrs); free(attrs_len); for (i = 0; i < dev->nb_buffer_attrs; i++) { strcpy(ptr, buffer_attrs[i]); ptr += buffer_attrs_len[i]; free(buffer_attrs[i]); } free(buffer_attrs); free(buffer_attrs_len); for (i = 0; i < dev->nb_debug_attrs; i++) { strcpy(ptr, debug_attrs[i]); ptr += debug_attrs_len[i]; free(debug_attrs[i]); } free(debug_attrs); free(debug_attrs_len); strcpy(ptr, ""); *length = ptr - str + sizeof("") - 1; return str; err_free_debug_attrs: while (k--) free(debug_attrs[k]); free(debug_attrs); err_free_debug_attrs_len: free(debug_attrs_len); err_free_buffer_attrs: while (k--) free(buffer_attrs[k]); free(buffer_attrs); err_free_buffer_attrs_len: free(buffer_attrs_len); err_free_channels: while (j--) free(channels[j]); free(channels); err_free_channels_len: free(channels_len); err_free_attrs: while (i--) free(attrs[i]); free(attrs); err_free_attrs_len: free(attrs_len); return NULL; } const char * iio_device_get_id(const struct iio_device *dev) { return dev->id; } const char * iio_device_get_name(const struct iio_device *dev) { return dev->name; } unsigned int iio_device_get_channels_count(const struct iio_device *dev) { return dev->nb_channels; } struct iio_channel * iio_device_get_channel(const struct iio_device *dev, unsigned int index) { if (index >= dev->nb_channels) return NULL; else return dev->channels[index]; } struct iio_channel * iio_device_find_channel(const struct iio_device *dev, const char *name, bool output) { unsigned int i; for (i = 0; i < dev->nb_channels; i++) { struct iio_channel *chn = dev->channels[i]; if (iio_channel_is_output(chn) != output) continue; if (!strcmp(chn->id, name) || (chn->name && !strcmp(chn->name, name))) return chn; } return NULL; } unsigned int iio_device_get_attrs_count(const struct iio_device *dev) { return dev->nb_attrs; } const char * iio_device_get_attr(const struct iio_device *dev, unsigned int index) { if (index >= dev->nb_attrs) return NULL; else return dev->attrs[index]; } const char * iio_device_find_attr(const struct iio_device *dev, const char *name) { unsigned int i; for (i = 0; i < dev->nb_attrs; i++) { const char *attr = dev->attrs[i]; if (!strcmp(attr, name)) return attr; } return NULL; } unsigned int iio_device_get_buffer_attrs_count(const struct iio_device *dev) { return dev->nb_buffer_attrs; } const char * iio_device_get_buffer_attr(const struct iio_device *dev, unsigned int index) { if (index >= dev->nb_buffer_attrs) return NULL; else return dev->buffer_attrs[index]; } const char * iio_device_find_buffer_attr(const struct iio_device *dev, const char *name) { unsigned int i; for (i = 0; i < dev->nb_buffer_attrs; i++) { const char *attr = dev->buffer_attrs[i]; if (!strcmp(attr, name)) return attr; } return NULL; } const char * iio_device_find_debug_attr(const struct iio_device *dev, const char *name) { unsigned int i; for (i = 0; i < dev->nb_debug_attrs; i++) { const char *attr = dev->debug_attrs[i]; if (!strcmp(attr, name)) return attr; } return NULL; } bool iio_device_is_tx(const struct iio_device *dev) { unsigned int i; for (i = 0; i < dev->nb_channels; i++) { struct iio_channel *ch = dev->channels[i]; if (iio_channel_is_output(ch) && iio_channel_is_enabled(ch)) return true; } return false; } int iio_device_open(const struct iio_device *dev, size_t samples_count, bool cyclic) { unsigned int i; bool has_channels = false; for (i = 0; !has_channels && i < dev->words; i++) has_channels = !!dev->mask[i]; if (!has_channels) return -EINVAL; if (dev->ctx->ops->open) return dev->ctx->ops->open(dev, samples_count, cyclic); else return -ENOSYS; } int iio_device_close(const struct iio_device *dev) { if (dev->ctx->ops->close) return dev->ctx->ops->close(dev); else return -ENOSYS; } int iio_device_get_poll_fd(const struct iio_device *dev) { if (dev->ctx->ops->get_fd) return dev->ctx->ops->get_fd(dev); else return -ENOSYS; } int iio_device_set_blocking_mode(const struct iio_device *dev, bool blocking) { if (dev->ctx->ops->set_blocking_mode) return dev->ctx->ops->set_blocking_mode(dev, blocking); else return -ENOSYS; } ssize_t iio_device_read_raw(const struct iio_device *dev, void *dst, size_t len, uint32_t *mask, size_t words) { if (dev->ctx->ops->read) return dev->ctx->ops->read(dev, dst, len, mask, words); else return -ENOSYS; } ssize_t iio_device_write_raw(const struct iio_device *dev, const void *src, size_t len) { if (dev->ctx->ops->write) return dev->ctx->ops->write(dev, src, len); else return -ENOSYS; } ssize_t iio_device_attr_read(const struct iio_device *dev, const char *attr, char *dst, size_t len) { if (dev->ctx->ops->read_device_attr) return dev->ctx->ops->read_device_attr(dev, attr, dst, len, IIO_ATTR_TYPE_DEVICE); else return -ENOSYS; } ssize_t iio_device_attr_write_raw(const struct iio_device *dev, const char *attr, const void *src, size_t len) { if (dev->ctx->ops->write_device_attr) return dev->ctx->ops->write_device_attr(dev, attr, src, len, IIO_ATTR_TYPE_DEVICE); else return -ENOSYS; } ssize_t iio_device_attr_write(const struct iio_device *dev, const char *attr, const char *src) { return iio_device_attr_write_raw(dev, attr, src, strlen(src) + 1); } ssize_t iio_device_buffer_attr_read(const struct iio_device *dev, const char *attr, char *dst, size_t len) { if (dev->ctx->ops->read_device_attr) return dev->ctx->ops->read_device_attr(dev, attr, dst, len, IIO_ATTR_TYPE_BUFFER); else return -ENOSYS; } ssize_t iio_device_buffer_attr_write_raw(const struct iio_device *dev, const char *attr, const void *src, size_t len) { if (dev->ctx->ops->write_device_attr) return dev->ctx->ops->write_device_attr(dev, attr, src, len, IIO_ATTR_TYPE_BUFFER); else return -ENOSYS; } ssize_t iio_device_buffer_attr_write(const struct iio_device *dev, const char *attr, const char *src) { return iio_device_buffer_attr_write_raw(dev, attr, src, strlen(src) + 1); } void iio_device_set_data(struct iio_device *dev, void *data) { dev->userdata = data; } void * iio_device_get_data(const struct iio_device *dev) { return dev->userdata; } bool iio_device_is_trigger(const struct iio_device *dev) { /* A trigger has a name, an id which starts by "trigger", * and zero channels. */ unsigned int nb = iio_device_get_channels_count(dev); const char *name = iio_device_get_name(dev), *id = iio_device_get_id(dev); return ((nb == 0) && !!name && !strncmp(id, "trigger", sizeof("trigger") - 1)); } int iio_device_set_kernel_buffers_count(const struct iio_device *dev, unsigned int nb_buffers) { if (nb_buffers == 0) return -EINVAL; else if (dev->ctx->ops->set_kernel_buffers_count) return dev->ctx->ops->set_kernel_buffers_count(dev, nb_buffers); else return -ENOSYS; } int iio_device_get_trigger(const struct iio_device *dev, const struct iio_device **trigger) { if (!trigger) return -EINVAL; else if (dev->ctx->ops->get_trigger) return dev->ctx->ops->get_trigger(dev, trigger); else return -ENOSYS; } int iio_device_set_trigger(const struct iio_device *dev, const struct iio_device *trigger) { if (trigger && !iio_device_is_trigger(trigger)) return -EINVAL; else if (dev->ctx->ops->set_trigger) return dev->ctx->ops->set_trigger(dev, trigger); else return -ENOSYS; } void free_device(struct iio_device *dev) { unsigned int i; for (i = 0; i < dev->nb_attrs; i++) free(dev->attrs[i]); if (dev->nb_attrs) free(dev->attrs); for (i = 0; i < dev->nb_buffer_attrs; i++) free(dev->buffer_attrs[i]); if (dev->nb_buffer_attrs) free(dev->buffer_attrs); for (i = 0; i < dev->nb_debug_attrs; i++) free(dev->debug_attrs[i]); if (dev->nb_debug_attrs) free(dev->debug_attrs); for (i = 0; i < dev->nb_channels; i++) free_channel(dev->channels[i]); if (dev->nb_channels) free(dev->channels); if (dev->mask) free(dev->mask); if (dev->name) free(dev->name); if (dev->id) free(dev->id); free(dev); } ssize_t iio_device_get_sample_size_mask(const struct iio_device *dev, const uint32_t *mask, size_t words) { ssize_t size = 0; unsigned int i; const struct iio_channel *prev = NULL; if (words != (dev->nb_channels + 31) / 32) return -EINVAL; for (i = 0; i < dev->nb_channels; i++) { const struct iio_channel *chn = dev->channels[i]; unsigned int length = chn->format.length / 8 * chn->format.repeat; if (chn->index < 0) break; if (!TEST_BIT(mask, chn->number)) continue; if (prev && chn->index == prev->index) { prev = chn; continue; } if (size % length) size += 2 * length - (size % length); else size += length; prev = chn; } return size; } ssize_t iio_device_get_sample_size(const struct iio_device *dev) { return iio_device_get_sample_size_mask(dev, dev->mask, dev->words); } int iio_device_attr_read_longlong(const struct iio_device *dev, const char *attr, long long *val) { char *end, buf[1024]; long long value; ssize_t ret = iio_device_attr_read(dev, attr, buf, sizeof(buf)); if (ret < 0) return (int) ret; value = strtoll(buf, &end, 0); if (end == buf) return -EINVAL; *val = value; return 0; } int iio_device_attr_read_bool(const struct iio_device *dev, const char *attr, bool *val) { long long value; int ret = iio_device_attr_read_longlong(dev, attr, &value); if (ret < 0) return ret; *val = !!value; return 0; } int iio_device_attr_read_double(const struct iio_device *dev, const char *attr, double *val) { char buf[1024]; ssize_t ret = iio_device_attr_read(dev, attr, buf, sizeof(buf)); if (ret < 0) return (int) ret; else return read_double(buf, val); } int iio_device_attr_write_longlong(const struct iio_device *dev, const char *attr, long long val) { ssize_t ret; char buf[1024]; iio_snprintf(buf, sizeof(buf), "%lld", val); ret = iio_device_attr_write(dev, attr, buf); return ret < 0 ? ret : 0; } int iio_device_attr_write_double(const struct iio_device *dev, const char *attr, double val) { ssize_t ret; char buf[1024]; ret = (ssize_t) write_double(buf, sizeof(buf), val); if (!ret) ret = iio_device_attr_write(dev, attr, buf); return ret < 0 ? ret : 0; } int iio_device_attr_write_bool(const struct iio_device *dev, const char *attr, bool val) { ssize_t ret; if (val) ret = iio_device_attr_write(dev, attr, "1"); else ret = iio_device_attr_write(dev, attr, "0"); return ret < 0 ? ret : 0; } int iio_device_buffer_attr_read_longlong(const struct iio_device *dev, const char *attr, long long *val) { char *end, buf[1024]; long long value; ssize_t ret = iio_device_buffer_attr_read(dev, attr, buf, sizeof(buf)); if (ret < 0) return (int) ret; value = strtoll(buf, &end, 0); if (end == buf) return -EINVAL; *val = value; return 0; } int iio_device_buffer_attr_read_bool(const struct iio_device *dev, const char *attr, bool *val) { long long value; int ret = iio_device_buffer_attr_read_longlong(dev, attr, &value); if (ret < 0) return ret; *val = !!value; return 0; } int iio_device_buffer_attr_read_double(const struct iio_device *dev, const char *attr, double *val) { char buf[1024]; ssize_t ret = iio_device_buffer_attr_read(dev, attr, buf, sizeof(buf)); if (ret < 0) return (int) ret; else return read_double(buf, val); } int iio_device_buffer_attr_write_longlong(const struct iio_device *dev, const char *attr, long long val) { ssize_t ret; char buf[1024]; iio_snprintf(buf, sizeof(buf), "%lld", val); ret = iio_device_buffer_attr_write(dev, attr, buf); return ret < 0 ? ret : 0; } int iio_device_buffer_attr_write_double(const struct iio_device *dev, const char *attr, double val) { ssize_t ret; char buf[1024]; ret = (ssize_t) write_double(buf, sizeof(buf), val); if (!ret) ret = iio_device_buffer_attr_write(dev, attr, buf); return ret < 0 ? ret : 0; } int iio_device_buffer_attr_write_bool(const struct iio_device *dev, const char *attr, bool val) { ssize_t ret; if (val) ret = iio_device_buffer_attr_write(dev, attr, "1"); else ret = iio_device_buffer_attr_write(dev, attr, "0"); return ret < 0 ? ret : 0; } ssize_t iio_device_debug_attr_read(const struct iio_device *dev, const char *attr, char *dst, size_t len) { if (dev->ctx->ops->read_device_attr) return dev->ctx->ops->read_device_attr(dev, attr, dst, len, IIO_ATTR_TYPE_DEBUG); else return -ENOSYS; } ssize_t iio_device_debug_attr_write_raw(const struct iio_device *dev, const char *attr, const void *src, size_t len) { if (dev->ctx->ops->write_device_attr) return dev->ctx->ops->write_device_attr(dev, attr, src, len, IIO_ATTR_TYPE_DEBUG); else return -ENOSYS; } ssize_t iio_device_debug_attr_write(const struct iio_device *dev, const char *attr, const char *src) { return iio_device_debug_attr_write_raw(dev, attr, src, strlen(src) + 1); } unsigned int iio_device_get_debug_attrs_count(const struct iio_device *dev) { return dev->nb_debug_attrs; } const char * iio_device_get_debug_attr(const struct iio_device *dev, unsigned int index) { if (index >= dev->nb_debug_attrs) return NULL; else return dev->debug_attrs[index]; } int iio_device_debug_attr_read_longlong(const struct iio_device *dev, const char *attr, long long *val) { char *end, buf[1024]; long long value; ssize_t ret = iio_device_debug_attr_read(dev, attr, buf, sizeof(buf)); if (ret < 0) return (int) ret; value = strtoll(buf, &end, 0); if (end == buf) return -EINVAL; *val = value; return 0; } int iio_device_debug_attr_read_bool(const struct iio_device *dev, const char *attr, bool *val) { long long value; int ret = iio_device_debug_attr_read_longlong(dev, attr, &value); if (ret < 0) return ret; *val = !!value; return 0; } int iio_device_debug_attr_read_double(const struct iio_device *dev, const char *attr, double *val) { char buf[1024]; ssize_t ret = iio_device_debug_attr_read(dev, attr, buf, sizeof(buf)); if (ret < 0) return (int) ret; else return read_double(buf, val); } int iio_device_debug_attr_write_longlong(const struct iio_device *dev, const char *attr, long long val) { ssize_t ret; char buf[1024]; iio_snprintf(buf, sizeof(buf), "%lld", val); ret = iio_device_debug_attr_write(dev, attr, buf); return ret < 0 ? ret : 0; } int iio_device_debug_attr_write_double(const struct iio_device *dev, const char *attr, double val) { ssize_t ret; char buf[1024]; ret = (ssize_t) write_double(buf, sizeof(buf), val); if (!ret) ret = iio_device_debug_attr_write(dev, attr, buf); return ret < 0 ? ret : 0; } int iio_device_debug_attr_write_bool(const struct iio_device *dev, const char *attr, bool val) { ssize_t ret; if (val) ret = iio_device_debug_attr_write_raw(dev, attr, "1", 2); else ret = iio_device_debug_attr_write_raw(dev, attr, "0", 2); return ret < 0 ? ret : 0; } int iio_device_identify_filename(const struct iio_device *dev, const char *filename, struct iio_channel **chn, const char **attr) { unsigned int i; for (i = 0; i < dev->nb_channels; i++) { struct iio_channel *ch = dev->channels[i]; unsigned int j; for (j = 0; j < ch->nb_attrs; j++) { if (!strcmp(ch->attrs[j].filename, filename)) { *attr = ch->attrs[j].name; *chn = ch; return 0; } } } for (i = 0; i < dev->nb_attrs; i++) { /* Devices attributes are named after their filename */ if (!strcmp(dev->attrs[i], filename)) { *attr = dev->attrs[i]; *chn = NULL; return 0; } } for (i = 0; i < dev->nb_debug_attrs; i++) { if (!strcmp(dev->debug_attrs[i], filename)) { *attr = dev->debug_attrs[i]; *chn = NULL; return 0; } } return -EINVAL; } int iio_device_reg_write(struct iio_device *dev, uint32_t address, uint32_t value) { ssize_t ret; char buf[1024]; iio_snprintf(buf, sizeof(buf), "0x%" PRIx32 " 0x%" PRIx32, address, value); ret = iio_device_debug_attr_write(dev, "direct_reg_access", buf); return ret < 0 ? ret : 0; } int iio_device_reg_read(struct iio_device *dev, uint32_t address, uint32_t *value) { /* NOTE: There is a race condition here. But it is extremely unlikely to * happen, and as this is a debug function, it shouldn't be used for * something else than debug. */ long long val; int ret = iio_device_debug_attr_write_longlong(dev, "direct_reg_access", (long long) address); if (ret < 0) return ret; ret = iio_device_debug_attr_read_longlong(dev, "direct_reg_access", &val); if (!ret) *value = (uint32_t) val; return ret; } static int read_each_attr(struct iio_device *dev, enum iio_attr_type type, int (*cb)(struct iio_device *dev, const char *attr, const char *val, size_t len, void *d), void *data) { int ret, buf_size; char *buf, *ptr; unsigned int i, count; /* We need a big buffer here; 1 MiB should be enough */ buf = malloc(0x100000); if (!buf) return -ENOMEM; switch(type){ case IIO_ATTR_TYPE_DEVICE: count = iio_device_get_attrs_count(dev); ret = (int) iio_device_attr_read(dev, NULL, buf, 0x100000); break; case IIO_ATTR_TYPE_DEBUG: count = iio_device_get_debug_attrs_count(dev); ret = (int) iio_device_debug_attr_read(dev, NULL, buf, 0x100000); break; case IIO_ATTR_TYPE_BUFFER: count = iio_device_get_buffer_attrs_count(dev); ret = (int) iio_device_buffer_attr_read(dev, NULL, buf, 0x100000); break; default: ret = -EINVAL; count = 0; break; } if (ret < 0) goto err_free_buf; ptr = buf; buf_size = ret; for (i = 0; i < count; i++) { const char *attr; int32_t len; if (buf_size < 4) { ret = -EPROTO; break; } len = (int32_t) iio_be32toh(*(uint32_t *) ptr); ptr += 4; buf_size -= 4; if (len > 0 && buf_size < len) { ret = -EPROTO; break; } switch(type){ case IIO_ATTR_TYPE_DEVICE: attr = iio_device_get_attr(dev, i); break; case IIO_ATTR_TYPE_DEBUG: attr = iio_device_get_debug_attr(dev, i); break; case IIO_ATTR_TYPE_BUFFER: attr = iio_device_get_buffer_attr(dev, i); break; default: attr = NULL; break; } if (len > 0) { ret = cb(dev, attr, ptr, (size_t) len, data); if (ret < 0) goto err_free_buf; if (len & 0x3) len = ((len >> 2) + 1) << 2; ptr += len; if (len >= buf_size) buf_size = 0; else buf_size -= len; } } err_free_buf: free(buf); return ret < 0 ? ret : 0; } static int write_each_attr(struct iio_device *dev, enum iio_attr_type type, ssize_t (*cb)(struct iio_device *dev, const char *attr, void *buf, size_t len, void *d), void *data) { char *buf, *ptr; unsigned int i, count; size_t len = 0x100000; int ret; /* We need a big buffer here; 1 MiB should be enough */ buf = malloc(len); if (!buf) return -ENOMEM; ptr = buf; switch(type){ case IIO_ATTR_TYPE_DEVICE: count = iio_device_get_attrs_count(dev); break; case IIO_ATTR_TYPE_DEBUG: count = iio_device_get_debug_attrs_count(dev); break; case IIO_ATTR_TYPE_BUFFER: count = iio_device_get_buffer_attrs_count(dev); break; default: ret = -EINVAL; goto err_free_buf; } for (i = 0; i < count; i++) { const char *attr; switch(type){ case IIO_ATTR_TYPE_DEVICE: attr = iio_device_get_attr(dev, i); break; case IIO_ATTR_TYPE_DEBUG: attr = iio_device_get_debug_attr(dev, i); break; case IIO_ATTR_TYPE_BUFFER: attr = iio_device_get_buffer_attr(dev, i); break; default: attr = NULL; break; } ret = (int) cb(dev, attr, ptr + 4, len - 4, data); if (ret < 0) goto err_free_buf; *(int32_t *) ptr = (int32_t) iio_htobe32((uint32_t) ret); ptr += 4; len -= 4; if (ret > 0) { if (ret & 0x3) ret = ((ret >> 2) + 1) << 2; ptr += ret; len -= ret; } } switch(type){ case IIO_ATTR_TYPE_DEVICE: ret = (int) iio_device_attr_write_raw(dev, NULL, buf, ptr - buf); break; case IIO_ATTR_TYPE_DEBUG: ret = (int) iio_device_debug_attr_write_raw(dev, NULL, buf, ptr - buf); break; case IIO_ATTR_TYPE_BUFFER: ret = (int) iio_device_buffer_attr_write_raw(dev, NULL, buf, ptr - buf); break; default: ret = -EINVAL; break; } err_free_buf: free(buf); return ret < 0 ? ret : 0; } int iio_device_debug_attr_read_all(struct iio_device *dev, int (*cb)(struct iio_device *dev, const char *attr, const char *val, size_t len, void *d), void *data) { return read_each_attr(dev, IIO_ATTR_TYPE_DEBUG, cb, data); } int iio_device_buffer_attr_read_all(struct iio_device *dev, int (*cb)(struct iio_device *dev, const char *attr, const char *val, size_t len, void *d), void *data) { return read_each_attr(dev, IIO_ATTR_TYPE_BUFFER, cb, data); } int iio_device_attr_read_all(struct iio_device *dev, int (*cb)(struct iio_device *dev, const char *attr, const char *val, size_t len, void *d), void *data) { return read_each_attr(dev, IIO_ATTR_TYPE_DEVICE ,cb, data); } int iio_device_debug_attr_write_all(struct iio_device *dev, ssize_t (*cb)(struct iio_device *dev, const char *attr, void *buf, size_t len, void *d), void *data) { return write_each_attr(dev, IIO_ATTR_TYPE_DEBUG, cb, data); } int iio_device_buffer_attr_write_all(struct iio_device *dev, ssize_t (*cb)(struct iio_device *dev, const char *attr, void *buf, size_t len, void *d), void *data) { return write_each_attr(dev, IIO_ATTR_TYPE_BUFFER, cb, data); } int iio_device_attr_write_all(struct iio_device *dev, ssize_t (*cb)(struct iio_device *dev, const char *attr, void *buf, size_t len, void *d), void *data) { return write_each_attr(dev, IIO_ATTR_TYPE_DEVICE, cb, data); } const struct iio_context * iio_device_get_context(const struct iio_device *dev) { return dev->ctx; }