iio: event_monitor: Enable events before monitoring
authorLinus Walleij <linus.walleij@linaro.org>
Fri, 19 Mar 2021 13:53:01 +0000 (14:53 +0100)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Thu, 25 Mar 2021 19:13:52 +0000 (19:13 +0000)
After some painful sessions with a driver that register an
enable/disable sysfs knob (gp2ap002) and manually going
in and enabling the event before monitoring it:

  cd /sys/bus/iio/devices/iio\:device2/events
  # ls
  in_proximity_thresh_either_en
  # echo 1 > in_proximity_thresh_either_en

I realized that it's better if the iio_event_monitor is
smart enough to enable all events by itself and disable them
after use, if passed the -a flag familiar from the
iio_generic_buffer tool.

Auto-enabling events depend on the hardware being able
to handle all events at the same time which isn't
necessarily the case, so a command line option is required
for this.

Cc: Bastien Nocera <hadess@hadess.net>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20210319135301.542911-1-linus.walleij@linaro.org
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
tools/iio/iio_event_monitor.c
tools/iio/iio_utils.h

index bb03859..0076437 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <unistd.h>
 #include <stdlib.h>
+#include <dirent.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <errno.h>
@@ -280,22 +281,69 @@ static void print_event(struct iio_event_data *event)
        printf("\n");
 }
 
+/* Enable or disable events in sysfs if the knob is available */
+static void enable_events(char *dev_dir, int enable)
+{
+       const struct dirent *ent;
+       char evdir[256];
+       int ret;
+       DIR *dp;
+
+       snprintf(evdir, sizeof(evdir), FORMAT_EVENTS_DIR, dev_dir);
+       evdir[sizeof(evdir)-1] = '\0';
+
+       dp = opendir(evdir);
+       if (!dp) {
+               fprintf(stderr, "Enabling/disabling events: can't open %s\n",
+                       evdir);
+               return;
+       }
+
+       while (ent = readdir(dp), ent) {
+               if (iioutils_check_suffix(ent->d_name, "_en")) {
+                       printf("%sabling: %s\n",
+                              enable ? "En" : "Dis",
+                              ent->d_name);
+                       ret = write_sysfs_int(ent->d_name, evdir,
+                                             enable);
+                       if (ret < 0)
+                               fprintf(stderr, "Failed to enable/disable %s\n",
+                                       ent->d_name);
+               }
+       }
+
+       if (closedir(dp) == -1) {
+               perror("Enabling/disabling channels: "
+                      "Failed to close directory");
+               return;
+       }
+}
+
 int main(int argc, char **argv)
 {
        struct iio_event_data event;
        const char *device_name;
+       char *dev_dir_name = NULL;
        char *chrdev_name;
        int ret;
        int dev_num;
        int fd, event_fd;
-
-       if (argc <= 1) {
-               fprintf(stderr, "Usage: %s <device_name>\n", argv[0]);
+       bool all_events = false;
+
+       if (argc == 2) {
+               device_name = argv[1];
+       } else if (argc == 3) {
+               device_name = argv[2];
+               if (!strcmp(argv[1], "-a"))
+                       all_events = true;
+       } else {
+               fprintf(stderr,
+                       "Usage: iio_event_monitor [options] <device_name>\n"
+                       "Listen and display events from IIO devices\n"
+                       "  -a         Auto-activate all available events\n");
                return -1;
        }
 
-       device_name = argv[1];
-
        dev_num = find_type_by_name(device_name, "iio:device");
        if (dev_num >= 0) {
                printf("Found IIO device with name %s with device number %d\n",
@@ -303,6 +351,10 @@ int main(int argc, char **argv)
                ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
                if (ret < 0)
                        return -ENOMEM;
+               /* Look up sysfs dir as well if we can */
+               ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
+               if (ret < 0)
+                       return -ENOMEM;
        } else {
                /*
                 * If we can't find an IIO device by name assume device_name is
@@ -313,6 +365,9 @@ int main(int argc, char **argv)
                        return -ENOMEM;
        }
 
+       if (all_events && dev_dir_name)
+               enable_events(dev_dir_name, 1);
+
        fd = open(chrdev_name, 0);
        if (fd == -1) {
                ret = -errno;
@@ -365,6 +420,10 @@ int main(int argc, char **argv)
                perror("Failed to close event file");
 
 error_free_chrdev_name:
+       /* Disable events after use */
+       if (all_events && dev_dir_name)
+               enable_events(dev_dir_name, 0);
+
        free(chrdev_name);
 
        return ret;
index 336752c..663c94a 100644 (file)
@@ -13,6 +13,7 @@
 #define IIO_MAX_NAME_LENGTH 64
 
 #define FORMAT_SCAN_ELEMENTS_DIR "%s/buffer%d"
+#define FORMAT_EVENTS_DIR "%s/events"
 #define FORMAT_TYPE_FILE "%s_type"
 
 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))