Message ID | 20210211122452.78106-18-alexandru.ardelean@analog.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | iio: core,buffer: add support for multiple IIO buffers per IIO device | expand |
On Thu, 11 Feb 2021 14:24:52 +0200 Alexandru Ardelean <alexandru.ardelean@analog.com> wrote: > This change makes use of the new IIO buffer API to read data from an IIO > buffer. > It doesn't read the /sys/bus/iio/devices/iio:deviceX/scan_elements dir > anymore, it reads /sys/bus/iio/devices/iio:deviceX/bufferY, where all the > scan_elements have been merged together with the old/classical buffer > attributes. > > And it makes use of the new IIO_BUFFER_GET_FD_IOCTL ioctl to get an FD for > the IIO buffer for which to read data from. > It also does a quick sanity check to see that -EBUSY is returned if reading > the chardev after the ioctl() has succeeded. > > This was tested with the following cases: > 1. Tested buffer0 works with ioctl() > 2. Tested that buffer0 can't be opened via /dev/iio:deviceX after ioctl() As mentioned below, this good to have but needs stronger comment next to it for anyone using this code as a basis for their own. Normally you just wouldn't try doing this! > 3. Moved valid buffer0 to be buffer1, and tested that data comes from it > > Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com> A few other things inline. Thanks, Jonathan > --- > tools/iio/Makefile | 1 + > tools/iio/iio_generic_buffer.c | 120 ++++++++++++++++++++++++++------- > tools/iio/iio_utils.c | 13 ++-- > tools/iio/iio_utils.h | 4 +- > 4 files changed, 105 insertions(+), 33 deletions(-) > > diff --git a/tools/iio/Makefile b/tools/iio/Makefile > index 3de763d9ab70..5d12ac4e7f8f 100644 > --- a/tools/iio/Makefile > +++ b/tools/iio/Makefile > @@ -27,6 +27,7 @@ include $(srctree)/tools/build/Makefile.include > # > $(OUTPUT)include/linux/iio: ../../include/uapi/linux/iio > mkdir -p $(OUTPUT)include/linux/iio 2>&1 || true > + ln -sf $(CURDIR)/../../include/uapi/linux/iio/buffer.h $@ > ln -sf $(CURDIR)/../../include/uapi/linux/iio/events.h $@ > ln -sf $(CURDIR)/../../include/uapi/linux/iio/types.h $@ > > diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c > index 7c7240553777..fdd08514d556 100644 > --- a/tools/iio/iio_generic_buffer.c > +++ b/tools/iio/iio_generic_buffer.c > @@ -30,6 +30,8 @@ > #include <inttypes.h> > #include <stdbool.h> > #include <signal.h> > +#include <sys/ioctl.h> > +#include <linux/iio/buffer.h> > #include "iio_utils.h" > > /** > @@ -197,7 +199,7 @@ static void process_scan(char *data, struct iio_channel_info *channels, > printf("\n"); > } > > -static int enable_disable_all_channels(char *dev_dir_name, int enable) > +static int enable_disable_all_channels(char *dev_dir_name, int buffer_idx, int enable) > { > const struct dirent *ent; > char scanelemdir[256]; > @@ -205,7 +207,7 @@ static int enable_disable_all_channels(char *dev_dir_name, int enable) > int ret; > > snprintf(scanelemdir, sizeof(scanelemdir), > - FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); > + FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name, buffer_idx); > scanelemdir[sizeof(scanelemdir)-1] = '\0'; > > dp = opendir(scanelemdir); > @@ -243,6 +245,7 @@ static void print_usage(void) > "Capture, convert and output data from IIO device buffer\n" > " -a Auto-activate all available channels\n" > " -A Force-activate ALL channels\n" > + " -b <n> The buffer which to open (by index), default 0\n" > " -c <n> Do n conversions, or loop forever if n < 0\n" > " -e Disable wait for event (new data)\n" > " -g Use trigger-less mode\n" > @@ -259,6 +262,7 @@ static void print_usage(void) > static enum autochan autochannels = AUTOCHANNELS_DISABLED; > static char *dev_dir_name = NULL; > static char *buf_dir_name = NULL; > +static int buffer_idx = 0; > static bool current_trigger_set = false; > > static void cleanup(void) > @@ -286,7 +290,7 @@ static void cleanup(void) > > /* Disable channels if auto-enabled */ > if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { > - ret = enable_disable_all_channels(dev_dir_name, 0); > + ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 0); > if (ret) > fprintf(stderr, "Failed to disable all channels\n"); > autochannels = AUTOCHANNELS_DISABLED; > @@ -333,7 +337,9 @@ int main(int argc, char **argv) > unsigned long long j; > unsigned long toread; > int ret, c; > - int fp = -1; > + struct stat st; > + int fd = -1; > + int buf_fd = -1; > > int num_channels = 0; > char *trigger_name = NULL, *device_name = NULL; > @@ -352,7 +358,7 @@ int main(int argc, char **argv) > > register_cleanup(); > > - while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, > + while ((c = getopt_long(argc, argv, "aAb:c:egl:n:N:t:T:w:?", longopts, > NULL)) != -1) { > switch (c) { > case 'a': > @@ -361,7 +367,20 @@ int main(int argc, char **argv) > case 'A': > autochannels = AUTOCHANNELS_ENABLED; > force_autochannels = true; > - break; > + break; > + case 'b': > + errno = 0; > + buffer_idx = strtoll(optarg, &dummy, 10); > + if (errno) { > + ret = -errno; > + goto error; > + } > + if (buffer_idx < 0) { > + ret = -ERANGE; > + goto error; > + } > + > + break; > case 'c': > errno = 0; > num_loops = strtoll(optarg, &dummy, 10); > @@ -518,7 +537,7 @@ int main(int argc, char **argv) > * Parse the files in scan_elements to identify what channels are > * present > */ > - ret = build_channel_array(dev_dir_name, &channels, &num_channels); > + ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels); > if (ret) { > fprintf(stderr, "Problem reading scan element information\n" > "diag %s\n", dev_dir_name); > @@ -535,7 +554,7 @@ int main(int argc, char **argv) > (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { > fprintf(stderr, "Enabling all channels\n"); > > - ret = enable_disable_all_channels(dev_dir_name, 1); > + ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 1); > if (ret) { > fprintf(stderr, "Failed to enable all channels\n"); > goto error; > @@ -544,7 +563,7 @@ int main(int argc, char **argv) > /* This flags that we need to disable the channels again */ > autochannels = AUTOCHANNELS_ACTIVE; > > - ret = build_channel_array(dev_dir_name, &channels, > + ret = build_channel_array(dev_dir_name, buffer_idx, &channels, > &num_channels); > if (ret) { > fprintf(stderr, "Problem reading scan element " > @@ -565,7 +584,7 @@ int main(int argc, char **argv) > fprintf(stderr, "Enable channels manually in " > FORMAT_SCAN_ELEMENTS_DIR > "/*_en or pass -a to autoenable channels and " > - "try again.\n", dev_dir_name); > + "try again.\n", dev_dir_name, buffer_idx); > ret = -ENOENT; > goto error; > } > @@ -576,12 +595,25 @@ int main(int argc, char **argv) > * be built rather than found. > */ > ret = asprintf(&buf_dir_name, > - "%siio:device%d/buffer", iio_dir, dev_num); > + "%siio:device%d/buffer%d", iio_dir, dev_num, buffer_idx); > if (ret < 0) { > ret = -ENOMEM; > goto error; > } > > + if (stat(buf_dir_name, &st)) { > + fprintf(stderr, "Could not stat() '%s', got error %d: %s\n", > + buf_dir_name, errno, strerror(errno)); > + ret = -errno; > + goto error; > + } > + > + if (!S_ISDIR(st.st_mode)) { > + fprintf(stderr, "File '%s' is not a directory\n", buf_dir_name); > + ret = -EFAULT; > + goto error; > + } > + > if (!notrigger) { > printf("%s %s\n", dev_dir_name, trigger_name); > /* > @@ -598,6 +630,37 @@ int main(int argc, char **argv) > } > } > > + ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); > + if (ret < 0) { > + ret = -ENOMEM; > + goto error; > + } > + > + /* Attempt to open non blocking the access dev */ No point in opening this one non blocking any more as only used for the ioctl. > + fd = open(buffer_access, O_RDONLY | O_NONBLOCK); > + if (fd == -1) { /* TODO: If it isn't there make the node */ > + ret = -errno; > + fprintf(stderr, "Failed to open %s\n", buffer_access); > + goto error; > + } > + > + /* specify for which buffer index we want an FD */ > + buf_fd = buffer_idx; > + > + ret = ioctl(fd, IIO_BUFFER_GET_FD_IOCTL, &buf_fd); > + if (ret == -1 || buf_fd == -1) { > + ret = -errno; > + if (ret == -ENODEV || ret == -EINVAL) > + fprintf(stderr, > + "This device does not support buffers\n"); This many buffers perhaps? > + else > + fprintf(stderr, "Failed to retrieve buffer fd\n"); > + if (close(fd) == -1) > + perror("Failed to close character device file"); Why close this here? > + > + goto error; > + } > + > /* Setup ring buffer parameters */ > ret = write_sysfs_int("length", buf_dir_name, buf_len); > if (ret < 0) > @@ -607,7 +670,8 @@ int main(int argc, char **argv) > ret = write_sysfs_int("enable", buf_dir_name, 1); > if (ret < 0) { > fprintf(stderr, > - "Failed to enable buffer: %s\n", strerror(-ret)); > + "Failed to enable buffer '%s': %s\n", > + buf_dir_name, strerror(-ret)); > goto error; > } > > @@ -618,24 +682,26 @@ int main(int argc, char **argv) > goto error; > } > > - ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); > - if (ret < 0) { > - ret = -ENOMEM; > - goto error; > + /* if this is buffer0, check that we get EBUSY after this point */ > + if (buffer_idx == 0) { Whilst this check is good from a sanity check point of view, I'd add a clear comment that there is no need to do this in a normal program! > + errno = 0; > + read_size = read(fd, data, 1); > + if (read_size > -1 || errno != EBUSY) { > + ret = -EFAULT; > + perror("Reading from '%s' should not be possible after ioctl()"); > + goto error; > + } > } > > - /* Attempt to open non blocking the access dev */ > - fp = open(buffer_access, O_RDONLY | O_NONBLOCK); > - if (fp == -1) { /* TODO: If it isn't there make the node */ > - ret = -errno; > - fprintf(stderr, "Failed to open %s\n", buffer_access); > - goto error; > - } > + /* close now the main chardev FD and let the buffer FD work */ > + if (close(fd) == -1) > + perror("Failed to close character device file"); > + fd = -1; > > for (j = 0; j < num_loops || num_loops < 0; j++) { > if (!noevents) { > struct pollfd pfd = { > - .fd = fp, > + .fd = buf_fd, > .events = POLLIN, > }; > > @@ -653,7 +719,7 @@ int main(int argc, char **argv) > toread = 64; > } > > - read_size = read(fp, data, toread * scan_size); > + read_size = read(buf_fd, data, toread * scan_size); > if (read_size < 0) { > if (errno == EAGAIN) { > fprintf(stderr, "nothing available\n"); > @@ -670,7 +736,9 @@ int main(int argc, char **argv) > error: > cleanup(); > > - if (fp >= 0 && close(fp) == -1) > + if (fd >= 0 && close(fd) == -1) > + perror("Failed to close character device"); > + if (buf_fd >= 0 && close(buf_fd) == -1) > perror("Failed to close buffer"); > free(buffer_access); > free(data); > diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c > index a96002f2c2d5..aadee6d34c74 100644 > --- a/tools/iio/iio_utils.c > +++ b/tools/iio/iio_utils.c > @@ -77,6 +77,7 @@ int iioutils_break_up_name(const char *full_name, char **generic_name) > * @mask: output a bit mask for the raw data > * @be: output if data in big endian > * @device_dir: the IIO device directory > + * @buffer_idx: the IIO buffer index > * @name: the channel name > * @generic_name: the channel type name > * > @@ -85,8 +86,8 @@ int iioutils_break_up_name(const char *full_name, char **generic_name) > static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, > unsigned int *bits_used, unsigned int *shift, > uint64_t *mask, unsigned int *be, > - const char *device_dir, const char *name, > - const char *generic_name) > + const char *device_dir, int buffer_idx, > + const char *name, const char *generic_name) > { > FILE *sysfsfp; > int ret; > @@ -96,7 +97,7 @@ static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, > unsigned padint; > const struct dirent *ent; > > - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); > + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx); > if (ret < 0) > return -ENOMEM; > > @@ -304,12 +305,13 @@ void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) > /** > * build_channel_array() - function to figure out what channels are present > * @device_dir: the IIO device directory in sysfs > + * @buffer_idx: the IIO buffer for this channel array > * @ci_array: output the resulting array of iio_channel_info > * @counter: output the amount of array elements > * > * Returns 0 on success, otherwise a negative error code. > **/ > -int build_channel_array(const char *device_dir, > +int build_channel_array(const char *device_dir, int buffer_idx, > struct iio_channel_info **ci_array, int *counter) > { > DIR *dp; > @@ -322,7 +324,7 @@ int build_channel_array(const char *device_dir, > char *filename; > > *counter = 0; > - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); > + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx); > if (ret < 0) > return -ENOMEM; > > @@ -503,6 +505,7 @@ int build_channel_array(const char *device_dir, > ¤t->mask, > ¤t->be, > device_dir, > + buffer_idx, > current->name, > current->generic_name); > if (ret < 0) > diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h > index a5d0aa8a57d3..336752cade4f 100644 > --- a/tools/iio/iio_utils.h > +++ b/tools/iio/iio_utils.h > @@ -12,7 +12,7 @@ > /* Made up value to limit allocation sizes */ > #define IIO_MAX_NAME_LENGTH 64 > > -#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" > +#define FORMAT_SCAN_ELEMENTS_DIR "%s/buffer%d" > #define FORMAT_TYPE_FILE "%s_type" > > #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) > @@ -61,7 +61,7 @@ int iioutils_get_param_float(float *output, const char *param_name, > const char *device_dir, const char *name, > const char *generic_name); > void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt); > -int build_channel_array(const char *device_dir, > +int build_channel_array(const char *device_dir, int buffer_idx, > struct iio_channel_info **ci_array, int *counter); > int find_type_by_name(const char *name, const char *type); > int write_sysfs_int(const char *filename, const char *basedir, int val);
diff --git a/tools/iio/Makefile b/tools/iio/Makefile index 3de763d9ab70..5d12ac4e7f8f 100644 --- a/tools/iio/Makefile +++ b/tools/iio/Makefile @@ -27,6 +27,7 @@ include $(srctree)/tools/build/Makefile.include # $(OUTPUT)include/linux/iio: ../../include/uapi/linux/iio mkdir -p $(OUTPUT)include/linux/iio 2>&1 || true + ln -sf $(CURDIR)/../../include/uapi/linux/iio/buffer.h $@ ln -sf $(CURDIR)/../../include/uapi/linux/iio/events.h $@ ln -sf $(CURDIR)/../../include/uapi/linux/iio/types.h $@ diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index 7c7240553777..fdd08514d556 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -30,6 +30,8 @@ #include <inttypes.h> #include <stdbool.h> #include <signal.h> +#include <sys/ioctl.h> +#include <linux/iio/buffer.h> #include "iio_utils.h" /** @@ -197,7 +199,7 @@ static void process_scan(char *data, struct iio_channel_info *channels, printf("\n"); } -static int enable_disable_all_channels(char *dev_dir_name, int enable) +static int enable_disable_all_channels(char *dev_dir_name, int buffer_idx, int enable) { const struct dirent *ent; char scanelemdir[256]; @@ -205,7 +207,7 @@ static int enable_disable_all_channels(char *dev_dir_name, int enable) int ret; snprintf(scanelemdir, sizeof(scanelemdir), - FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); + FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name, buffer_idx); scanelemdir[sizeof(scanelemdir)-1] = '\0'; dp = opendir(scanelemdir); @@ -243,6 +245,7 @@ static void print_usage(void) "Capture, convert and output data from IIO device buffer\n" " -a Auto-activate all available channels\n" " -A Force-activate ALL channels\n" + " -b <n> The buffer which to open (by index), default 0\n" " -c <n> Do n conversions, or loop forever if n < 0\n" " -e Disable wait for event (new data)\n" " -g Use trigger-less mode\n" @@ -259,6 +262,7 @@ static void print_usage(void) static enum autochan autochannels = AUTOCHANNELS_DISABLED; static char *dev_dir_name = NULL; static char *buf_dir_name = NULL; +static int buffer_idx = 0; static bool current_trigger_set = false; static void cleanup(void) @@ -286,7 +290,7 @@ static void cleanup(void) /* Disable channels if auto-enabled */ if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { - ret = enable_disable_all_channels(dev_dir_name, 0); + ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 0); if (ret) fprintf(stderr, "Failed to disable all channels\n"); autochannels = AUTOCHANNELS_DISABLED; @@ -333,7 +337,9 @@ int main(int argc, char **argv) unsigned long long j; unsigned long toread; int ret, c; - int fp = -1; + struct stat st; + int fd = -1; + int buf_fd = -1; int num_channels = 0; char *trigger_name = NULL, *device_name = NULL; @@ -352,7 +358,7 @@ int main(int argc, char **argv) register_cleanup(); - while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, + while ((c = getopt_long(argc, argv, "aAb:c:egl:n:N:t:T:w:?", longopts, NULL)) != -1) { switch (c) { case 'a': @@ -361,7 +367,20 @@ int main(int argc, char **argv) case 'A': autochannels = AUTOCHANNELS_ENABLED; force_autochannels = true; - break; + break; + case 'b': + errno = 0; + buffer_idx = strtoll(optarg, &dummy, 10); + if (errno) { + ret = -errno; + goto error; + } + if (buffer_idx < 0) { + ret = -ERANGE; + goto error; + } + + break; case 'c': errno = 0; num_loops = strtoll(optarg, &dummy, 10); @@ -518,7 +537,7 @@ int main(int argc, char **argv) * Parse the files in scan_elements to identify what channels are * present */ - ret = build_channel_array(dev_dir_name, &channels, &num_channels); + ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels); if (ret) { fprintf(stderr, "Problem reading scan element information\n" "diag %s\n", dev_dir_name); @@ -535,7 +554,7 @@ int main(int argc, char **argv) (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { fprintf(stderr, "Enabling all channels\n"); - ret = enable_disable_all_channels(dev_dir_name, 1); + ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 1); if (ret) { fprintf(stderr, "Failed to enable all channels\n"); goto error; @@ -544,7 +563,7 @@ int main(int argc, char **argv) /* This flags that we need to disable the channels again */ autochannels = AUTOCHANNELS_ACTIVE; - ret = build_channel_array(dev_dir_name, &channels, + ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels); if (ret) { fprintf(stderr, "Problem reading scan element " @@ -565,7 +584,7 @@ int main(int argc, char **argv) fprintf(stderr, "Enable channels manually in " FORMAT_SCAN_ELEMENTS_DIR "/*_en or pass -a to autoenable channels and " - "try again.\n", dev_dir_name); + "try again.\n", dev_dir_name, buffer_idx); ret = -ENOENT; goto error; } @@ -576,12 +595,25 @@ int main(int argc, char **argv) * be built rather than found. */ ret = asprintf(&buf_dir_name, - "%siio:device%d/buffer", iio_dir, dev_num); + "%siio:device%d/buffer%d", iio_dir, dev_num, buffer_idx); if (ret < 0) { ret = -ENOMEM; goto error; } + if (stat(buf_dir_name, &st)) { + fprintf(stderr, "Could not stat() '%s', got error %d: %s\n", + buf_dir_name, errno, strerror(errno)); + ret = -errno; + goto error; + } + + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "File '%s' is not a directory\n", buf_dir_name); + ret = -EFAULT; + goto error; + } + if (!notrigger) { printf("%s %s\n", dev_dir_name, trigger_name); /* @@ -598,6 +630,37 @@ int main(int argc, char **argv) } } + ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error; + } + + /* Attempt to open non blocking the access dev */ + fd = open(buffer_access, O_RDONLY | O_NONBLOCK); + if (fd == -1) { /* TODO: If it isn't there make the node */ + ret = -errno; + fprintf(stderr, "Failed to open %s\n", buffer_access); + goto error; + } + + /* specify for which buffer index we want an FD */ + buf_fd = buffer_idx; + + ret = ioctl(fd, IIO_BUFFER_GET_FD_IOCTL, &buf_fd); + if (ret == -1 || buf_fd == -1) { + ret = -errno; + if (ret == -ENODEV || ret == -EINVAL) + fprintf(stderr, + "This device does not support buffers\n"); + else + fprintf(stderr, "Failed to retrieve buffer fd\n"); + if (close(fd) == -1) + perror("Failed to close character device file"); + + goto error; + } + /* Setup ring buffer parameters */ ret = write_sysfs_int("length", buf_dir_name, buf_len); if (ret < 0) @@ -607,7 +670,8 @@ int main(int argc, char **argv) ret = write_sysfs_int("enable", buf_dir_name, 1); if (ret < 0) { fprintf(stderr, - "Failed to enable buffer: %s\n", strerror(-ret)); + "Failed to enable buffer '%s': %s\n", + buf_dir_name, strerror(-ret)); goto error; } @@ -618,24 +682,26 @@ int main(int argc, char **argv) goto error; } - ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error; + /* if this is buffer0, check that we get EBUSY after this point */ + if (buffer_idx == 0) { + errno = 0; + read_size = read(fd, data, 1); + if (read_size > -1 || errno != EBUSY) { + ret = -EFAULT; + perror("Reading from '%s' should not be possible after ioctl()"); + goto error; + } } - /* Attempt to open non blocking the access dev */ - fp = open(buffer_access, O_RDONLY | O_NONBLOCK); - if (fp == -1) { /* TODO: If it isn't there make the node */ - ret = -errno; - fprintf(stderr, "Failed to open %s\n", buffer_access); - goto error; - } + /* close now the main chardev FD and let the buffer FD work */ + if (close(fd) == -1) + perror("Failed to close character device file"); + fd = -1; for (j = 0; j < num_loops || num_loops < 0; j++) { if (!noevents) { struct pollfd pfd = { - .fd = fp, + .fd = buf_fd, .events = POLLIN, }; @@ -653,7 +719,7 @@ int main(int argc, char **argv) toread = 64; } - read_size = read(fp, data, toread * scan_size); + read_size = read(buf_fd, data, toread * scan_size); if (read_size < 0) { if (errno == EAGAIN) { fprintf(stderr, "nothing available\n"); @@ -670,7 +736,9 @@ int main(int argc, char **argv) error: cleanup(); - if (fp >= 0 && close(fp) == -1) + if (fd >= 0 && close(fd) == -1) + perror("Failed to close character device"); + if (buf_fd >= 0 && close(buf_fd) == -1) perror("Failed to close buffer"); free(buffer_access); free(data); diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c index a96002f2c2d5..aadee6d34c74 100644 --- a/tools/iio/iio_utils.c +++ b/tools/iio/iio_utils.c @@ -77,6 +77,7 @@ int iioutils_break_up_name(const char *full_name, char **generic_name) * @mask: output a bit mask for the raw data * @be: output if data in big endian * @device_dir: the IIO device directory + * @buffer_idx: the IIO buffer index * @name: the channel name * @generic_name: the channel type name * @@ -85,8 +86,8 @@ int iioutils_break_up_name(const char *full_name, char **generic_name) static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, unsigned int *bits_used, unsigned int *shift, uint64_t *mask, unsigned int *be, - const char *device_dir, const char *name, - const char *generic_name) + const char *device_dir, int buffer_idx, + const char *name, const char *generic_name) { FILE *sysfsfp; int ret; @@ -96,7 +97,7 @@ static int iioutils_get_type(unsigned int *is_signed, unsigned int *bytes, unsigned padint; const struct dirent *ent; - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx); if (ret < 0) return -ENOMEM; @@ -304,12 +305,13 @@ void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) /** * build_channel_array() - function to figure out what channels are present * @device_dir: the IIO device directory in sysfs + * @buffer_idx: the IIO buffer for this channel array * @ci_array: output the resulting array of iio_channel_info * @counter: output the amount of array elements * * Returns 0 on success, otherwise a negative error code. **/ -int build_channel_array(const char *device_dir, +int build_channel_array(const char *device_dir, int buffer_idx, struct iio_channel_info **ci_array, int *counter) { DIR *dp; @@ -322,7 +324,7 @@ int build_channel_array(const char *device_dir, char *filename; *counter = 0; - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir, buffer_idx); if (ret < 0) return -ENOMEM; @@ -503,6 +505,7 @@ int build_channel_array(const char *device_dir, ¤t->mask, ¤t->be, device_dir, + buffer_idx, current->name, current->generic_name); if (ret < 0) diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h index a5d0aa8a57d3..336752cade4f 100644 --- a/tools/iio/iio_utils.h +++ b/tools/iio/iio_utils.h @@ -12,7 +12,7 @@ /* Made up value to limit allocation sizes */ #define IIO_MAX_NAME_LENGTH 64 -#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" +#define FORMAT_SCAN_ELEMENTS_DIR "%s/buffer%d" #define FORMAT_TYPE_FILE "%s_type" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) @@ -61,7 +61,7 @@ int iioutils_get_param_float(float *output, const char *param_name, const char *device_dir, const char *name, const char *generic_name); void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt); -int build_channel_array(const char *device_dir, +int build_channel_array(const char *device_dir, int buffer_idx, struct iio_channel_info **ci_array, int *counter); int find_type_by_name(const char *name, const char *type); int write_sysfs_int(const char *filename, const char *basedir, int val);
This change makes use of the new IIO buffer API to read data from an IIO buffer. It doesn't read the /sys/bus/iio/devices/iio:deviceX/scan_elements dir anymore, it reads /sys/bus/iio/devices/iio:deviceX/bufferY, where all the scan_elements have been merged together with the old/classical buffer attributes. And it makes use of the new IIO_BUFFER_GET_FD_IOCTL ioctl to get an FD for the IIO buffer for which to read data from. It also does a quick sanity check to see that -EBUSY is returned if reading the chardev after the ioctl() has succeeded. This was tested with the following cases: 1. Tested buffer0 works with ioctl() 2. Tested that buffer0 can't be opened via /dev/iio:deviceX after ioctl() 3. Moved valid buffer0 to be buffer1, and tested that data comes from it Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com> --- tools/iio/Makefile | 1 + tools/iio/iio_generic_buffer.c | 120 ++++++++++++++++++++++++++------- tools/iio/iio_utils.c | 13 ++-- tools/iio/iio_utils.h | 4 +- 4 files changed, 105 insertions(+), 33 deletions(-)