static ssize_t network_read(const struct iio_device *dev, void *dst, size_t len, uint32_t *mask, size_t words) { uintptr_t ptr = (uintptr_t) dst; struct iio_device_pdata *pdata = dev->pdata; int fd = pdata->fd; ssize_t ret, read = 0; char buf[1024]; if (!len || words != (dev->nb_channels + 31) / 32) return -EINVAL; snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n", dev->id, (unsigned long) len); network_lock_dev(pdata); ret = write_rwbuf_command(dev, buf, false); if (ret < 0) { network_unlock_dev(pdata); return ret; } do { ret = network_read_mask(fd, mask, words); if (!ret) break; if (ret < 0) { iio_strerror(-ret, buf, sizeof(buf)); ERROR("Unable to read mask: %s\n", buf); network_unlock_dev(pdata); return read ? read : ret; } mask = NULL; /* We read the mask only once */ ret = read_all((void *) ptr, ret, fd); if (ret < 0) { iio_strerror(-ret, buf, sizeof(buf)); ERROR("Unable to read response to READ: %s\n", buf); network_unlock_dev(pdata); return read ? read : ret; } ptr += ret; read += ret; len -= ret; } while (len); network_unlock_dev(pdata); return read; }
static ssize_t network_get_buffer(const struct iio_device *dev, void **addr_ptr, size_t bytes_used, uint32_t *mask, size_t words) { struct iio_device_pdata *pdata = dev->pdata; ssize_t ret, read = 0; int memfd; bool tx; if (pdata->is_cyclic) return -ENOSYS; /* We check early that the temporary file can be created, so that we can * return -ENOSYS in case it fails, which will indicate that the * high-speed interface is not available. * * O_TMPFILE -> Linux 3.11. * TODO: use memfd_create (Linux 3.17) */ memfd = open(P_tmpdir, O_RDWR | O_TMPFILE | O_EXCL, S_IRWXU); if (memfd < 0) return -ENOSYS; if (!addr_ptr || words != (dev->nb_channels + 31) / 32) { close(memfd); return -EINVAL; } if (pdata->mmap_addr) munmap(pdata->mmap_addr, pdata->mmap_len); if (pdata->mmap_addr && pdata->is_tx) { char buf[1024]; snprintf(buf, sizeof(buf), "WRITEBUF %s %lu\r\n", dev->id, (unsigned long) bytes_used); iio_mutex_lock(pdata->lock); ret = write_rwbuf_command(dev, buf, false); if (ret < 0) goto err_close_memfd; ret = network_do_splice(pdata->fd, pdata->memfd, bytes_used); if (ret < 0) goto err_close_memfd; pdata->wait_for_err_code = true; iio_mutex_unlock(pdata->lock); } if (pdata->memfd >= 0) close(pdata->memfd); pdata->memfd = memfd; ret = (ssize_t) ftruncate(pdata->memfd, pdata->mmap_len); if (ret < 0) { ret = -errno; ERROR("Unable to truncate temp file: %zi\n", -ret); return ret; } if (!pdata->is_tx) { char buf[1024]; size_t len = pdata->mmap_len; snprintf(buf, sizeof(buf), "READBUF %s %lu\r\n", dev->id, (unsigned long) len); iio_mutex_lock(pdata->lock); ret = write_rwbuf_command(dev, buf, false); if (ret < 0) goto err_unlock; do { ret = network_read_mask(pdata->fd, mask, words); if (!ret) break; if (ret < 0) goto err_unlock; mask = NULL; /* We read the mask only once */ ret = network_do_splice(pdata->memfd, pdata->fd, ret); if (ret < 0) goto err_unlock; read += ret; len -= ret; } while (len); iio_mutex_unlock(pdata->lock); } pdata->mmap_addr = mmap(NULL, pdata->mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, pdata->memfd, 0); if (pdata->mmap_addr == MAP_FAILED) { pdata->mmap_addr = NULL; ret = -errno; ERROR("Unable to mmap: %zi\n", -ret); return ret; } *addr_ptr = pdata->mmap_addr; return read ? read : bytes_used; err_close_memfd: close(memfd); err_unlock: iio_mutex_unlock(pdata->lock); return ret; }