diff --git a/compat.c b/compat.c index cc1358963..633485eb4 100644 --- a/compat.c +++ b/compat.c @@ -972,7 +972,10 @@ ssize_t iio_device_attr_read(const struct iio_device *dev, const struct iio_attr *attr; attr = IIO_CALL(iio_device_find_attr)(dev, name); - return IIO_CALL(iio_attr_read_raw)(attr, dst, len); + if (attr) + return IIO_CALL(iio_attr_read_raw)(attr, dst, len); + + return -ENOENT; } int iio_device_attr_read_bool(const struct iio_device *dev, @@ -981,7 +984,10 @@ int iio_device_attr_read_bool(const struct iio_device *dev, const struct iio_attr *attr; attr = IIO_CALL(iio_device_find_attr)(dev, name); - return IIO_CALL(iio_attr_read_bool)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_bool)(attr, val); + + return -ENOENT; } int iio_device_attr_read_longlong(const struct iio_device *dev, @@ -990,7 +996,10 @@ int iio_device_attr_read_longlong(const struct iio_device *dev, const struct iio_attr *attr; attr = IIO_CALL(iio_device_find_attr)(dev, name); - return IIO_CALL(iio_attr_read_longlong)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_longlong)(attr, val); + + return -ENOENT; } int iio_device_attr_read_double(const struct iio_device *dev, @@ -999,7 +1008,10 @@ int iio_device_attr_read_double(const struct iio_device *dev, const struct iio_attr *attr; attr = IIO_CALL(iio_device_find_attr)(dev, name); - return IIO_CALL(iio_attr_read_double)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_double)(attr, val); + + return -ENOENT; } int iio_device_attr_read_all(struct iio_device *dev, @@ -1159,7 +1171,10 @@ ssize_t iio_device_debug_attr_read(const struct iio_device *dev, const struct iio_attr *attr; attr = IIO_CALL(iio_device_find_debug_attr)(dev, name); - return IIO_CALL(iio_attr_read_raw)(attr, dst, len); + if (attr) + return IIO_CALL(iio_attr_read_raw)(attr, dst, len); + + return -ENOENT; } int iio_device_debug_attr_read_bool(const struct iio_device *dev, @@ -1168,7 +1183,10 @@ int iio_device_debug_attr_read_bool(const struct iio_device *dev, const struct iio_attr *attr; attr = IIO_CALL(iio_device_find_debug_attr)(dev, name); - return IIO_CALL(iio_attr_read_bool)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_bool)(attr, val); + + return -ENOENT; } int iio_device_debug_attr_read_longlong(const struct iio_device *dev, @@ -1177,7 +1195,10 @@ int iio_device_debug_attr_read_longlong(const struct iio_device *dev, const struct iio_attr *attr; attr = IIO_CALL(iio_device_find_debug_attr)(dev, name); - return IIO_CALL(iio_attr_read_longlong)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_longlong)(attr, val); + + return -ENOENT; } int iio_device_debug_attr_read_double(const struct iio_device *dev, @@ -1186,7 +1207,10 @@ int iio_device_debug_attr_read_double(const struct iio_device *dev, const struct iio_attr *attr; attr = IIO_CALL(iio_device_find_debug_attr)(dev, name); - return IIO_CALL(iio_attr_read_double)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_double)(attr, val); + + return -ENOENT; } int iio_device_debug_attr_read_all(struct iio_device *dev, @@ -1661,13 +1685,29 @@ const char * iio_channel_find_attr(const struct iio_channel *chn, return IIO_CALL(iio_attr_get_name)(attr); } +const char * iio_channel_attr_get_filename(const struct iio_channel *chn, + const char *name) +{ + const struct iio_attr *attr; + + attr = IIO_CALL(iio_channel_find_attr)(chn, name); + if (!attr) + return NULL; + + return IIO_CALL(iio_attr_get_filename)(attr); +} + + ssize_t iio_channel_attr_read(const struct iio_channel *chn, const char *name, char *dst, size_t len) { const struct iio_attr *attr; attr = IIO_CALL(iio_channel_find_attr)(chn, name); - return IIO_CALL(iio_attr_read_raw)(attr, dst, len); + if (attr) + return IIO_CALL(iio_attr_read_raw)(attr, dst, len); + + return -ENOENT; } int iio_channel_attr_read_bool(const struct iio_channel *chn, @@ -1676,7 +1716,10 @@ int iio_channel_attr_read_bool(const struct iio_channel *chn, const struct iio_attr *attr; attr = IIO_CALL(iio_channel_find_attr)(chn, name); - return IIO_CALL(iio_attr_read_bool)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_bool)(attr, val); + + return -ENOENT; } int iio_channel_attr_read_longlong(const struct iio_channel *chn, @@ -1685,7 +1728,10 @@ int iio_channel_attr_read_longlong(const struct iio_channel *chn, const struct iio_attr *attr; attr = IIO_CALL(iio_channel_find_attr)(chn, name); - return IIO_CALL(iio_attr_read_longlong)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_longlong)(attr, val); + + return -ENOENT; } int iio_channel_attr_read_double(const struct iio_channel *chn, @@ -1694,7 +1740,10 @@ int iio_channel_attr_read_double(const struct iio_channel *chn, const struct iio_attr *attr; attr = IIO_CALL(iio_channel_find_attr)(chn, name); - return IIO_CALL(iio_attr_read_double)(attr, val); + if (attr) + return IIO_CALL(iio_attr_read_double)(attr, val); + + return -ENOENT; } int iio_channel_attr_read_all(struct iio_channel *chn, diff --git a/iiod/ops.c b/iiod/ops.c index 4d4611faa..b4c5a45f5 100644 --- a/iiod/ops.c +++ b/iiod/ops.c @@ -1302,6 +1302,110 @@ ssize_t rw_dev(struct parser_pdata *pdata, struct iio_device *dev, return ret; } +static inline uint32_t iiod_htobe32(uint32_t word) +{ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return word; +#elif defined(__GNUC__) + return __builtin_bswap32(word); +#else + return ((word & 0xff) << 24) | ((word & 0xff00) << 8) | + ((word >> 8) & 0xff00) | ((word >> 24) & 0xff); +#endif +} + +static inline uint32_t iiod_be32toh(uint32_t word) +{ + return iiod_htobe32(word); +} + +typedef struct iio_attr * (*rw_attr_cb_t)(const void *, unsigned int); + +static int buffer_analyze(unsigned int nb, const char *src, size_t len) +{ + while (nb--) { + int32_t val; + + if (len < 4) + return -EINVAL; + + val = (int32_t) iiod_be32toh(*(uint32_t *) src); + src += 4; + len -= 4; + + if (val > 0) { + if ((uint32_t) val > len) + return -EINVAL; + + /* Align the length to 4 bytes */ + if (val & 3) + val = ((val >> 2) + 1) << 2; + len -= val; + src += val; + } + } + + /* We should have analyzed the whole buffer by now */ + return !len ? 0 : -EINVAL; +} + +static ssize_t read_each_attr(const void *iio, char *buf, size_t len, + unsigned int nb, rw_attr_cb_t cb) +{ + const struct iio_attr *attr; + unsigned int i; + char *ptr = buf; + ssize_t ret; + + for (i = 0; len >= 4 && i < nb; i++) { + attr = (*cb)(iio, i); + if (!attr) + ret = -ENOENT; + else + ret = iio_attr_read_raw(attr, ptr + 4, len - 4); + *(uint32_t *)ptr = iiod_htobe32(ret); + + /* Align the length to 4 bytes */ + ret = ret < 0 ? 0 : (ret + 3) & ~0x3; + ptr += 4 + ret; + len -= 4 + ret; + } + + return ptr - buf; +} + +static ssize_t write_each_attr(const void *iio, const char *buf, size_t len, + unsigned int nb, rw_attr_cb_t cb) +{ + const struct iio_attr *attr; + const char *ptr = buf; + unsigned int i; + ssize_t ret; + int32_t val; + + ret = buffer_analyze(nb, buf, len); + if (ret < 0) + return ret; + + for (i = 0; i < nb; i++) { + val = (int32_t) iiod_be32toh(*(uint32_t *)ptr); + ptr += 4; + + if (val > 0) { + attr = (*cb)(iio, i); + if (!attr) + continue; + + iio_attr_write_raw(attr, ptr, val); + + /* Align the length to 4 bytes */ + ptr += (val + 3) & ~0x3; + } + } + + return ptr - buf; +} + ssize_t read_dev_attr(struct parser_pdata *pdata, struct iio_device *dev, const char *name, enum iio_attr_type type) { @@ -1312,12 +1416,32 @@ ssize_t read_dev_attr(struct parser_pdata *pdata, struct iio_device *dev, * of data. */ char buf[0x10000]; ssize_t ret = -EINVAL; + unsigned int nb; if (!dev) { print_value(pdata, -ENODEV); return -ENODEV; } + if (!name) { + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + nb = iio_device_get_attrs_count(dev); + ret = read_each_attr(dev, buf, sizeof(buf) - 1, nb, + (rw_attr_cb_t)iio_device_get_attr); + break; + case IIO_ATTR_TYPE_DEBUG: + nb = iio_device_get_debug_attrs_count(dev); + ret = read_each_attr(dev, buf, sizeof(buf) - 1, nb, + (rw_attr_cb_t)iio_device_get_debug_attr); + break; + default: + return -EINVAL; + } + + goto out_print_value; + } + switch (type) { case IIO_ATTR_TYPE_DEVICE: attr = iio_device_find_attr(dev, name); @@ -1354,6 +1478,7 @@ ssize_t read_dev_attr(struct parser_pdata *pdata, struct iio_device *dev, break; } +out_print_value: print_value(pdata, ret); if (ret < 0) return ret; @@ -1367,21 +1492,41 @@ ssize_t write_dev_attr(struct parser_pdata *pdata, struct iio_device *dev, { const struct iio_device_pdata *dev_pdata; const struct iio_attr *attr; + unsigned int nb; ssize_t ret = -ENOMEM; char *buf; if (!dev) { ret = -ENODEV; - goto err_print_value; + goto out_print_value; } buf = malloc(len); if (!buf) - goto err_print_value; + goto out_print_value; ret = read_all(pdata, buf, len); if (ret < 0) - goto err_free_buffer; + goto out_free_buffer; + + if (!name) { + switch (type) { + case IIO_ATTR_TYPE_DEVICE: + nb = iio_device_get_attrs_count(dev); + ret = write_each_attr(dev, buf, len - 1, nb, + (rw_attr_cb_t)iio_device_get_attr); + break; + case IIO_ATTR_TYPE_DEBUG: + nb = iio_device_get_debug_attrs_count(dev); + ret = write_each_attr(dev, buf, len - 1, nb, + (rw_attr_cb_t)iio_device_get_debug_attr); + break; + default: + return -EINVAL; + } + + goto out_print_value; + } switch (type) { case IIO_ATTR_TYPE_DEVICE: @@ -1419,9 +1564,9 @@ ssize_t write_dev_attr(struct parser_pdata *pdata, struct iio_device *dev, break; } -err_free_buffer: +out_free_buffer: free(buf); -err_print_value: +out_print_value: print_value(pdata, ret); return ret; } @@ -1429,20 +1574,32 @@ ssize_t write_dev_attr(struct parser_pdata *pdata, struct iio_device *dev, ssize_t read_chn_attr(struct parser_pdata *pdata, struct iio_channel *chn, const char *name) { - char buf[1024]; + /* We use a very large buffer here, as if attr is NULL all the + * attributes will be read, which may represents a few kilobytes worth + * of data. */ + char buf[0x10000]; ssize_t ret = -ENODEV; const struct iio_attr *attr; + unsigned int nb; - if (chn) { + if (!chn) { + ret = pdata->dev ? -ENXIO : -ENODEV; + goto out_print_value; + } + + if (!name) { + nb = iio_channel_get_attrs_count(chn); + ret = read_each_attr(chn, buf, sizeof(buf) - 1, nb, + (rw_attr_cb_t)iio_channel_get_attr); + } else { attr = iio_channel_find_attr(chn, name); if (attr) ret = iio_attr_read_raw(attr, buf, sizeof(buf) - 1); else ret = -ENOENT; - } else { - ret = pdata->dev ? -ENXIO : -ENODEV; } +out_print_value: print_value(pdata, ret); if (ret < 0) return ret; @@ -1456,6 +1613,7 @@ ssize_t write_chn_attr(struct parser_pdata *pdata, { const struct iio_attr *attr; ssize_t ret = -ENOMEM; + unsigned int nb; char *buf; buf = malloc(len); @@ -1466,14 +1624,21 @@ ssize_t write_chn_attr(struct parser_pdata *pdata, if (ret < 0) goto err_free_buffer; - if (chn) { + if (!chn) { + ret = pdata->dev ? -ENXIO : -ENODEV; + goto err_free_buffer; + } + + if (!name) { + nb = iio_channel_get_attrs_count(chn); + ret = write_each_attr(chn, buf, sizeof(buf) - 1, nb, + (rw_attr_cb_t)iio_channel_get_attr); + } else { attr = iio_channel_find_attr(chn, name); if (attr) ret = iio_attr_write_raw(attr, buf, len); else ret = -ENOENT; - } else { - ret = pdata->dev ? -ENXIO : -ENODEV; } err_free_buffer: diff --git a/network.c b/network.c index d6482b25a..4e6dcb3d2 100644 --- a/network.c +++ b/network.c @@ -536,7 +536,7 @@ static const struct iio_backend_ops network_ops = { __api_export_if(WITH_NETWORK_BACKEND_DYNAMIC) const struct iio_backend iio_ip_backend = { .api_version = IIO_BACKEND_API_V1, - .name = "network", + .name = "ip", .uri_prefix = "ip:", .ops = &network_ops, .default_timeout_ms = NETWORK_TIMEOUT_MS,