Linux GPIO subsystem development
 help / color / mirror / Atom feed
From: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
To: Linus Walleij <linus.walleij@linaro.org>,
	Kent Gibson <warthog618@gmail.com>,
	Vincent Fazio <vfazio@xes-inc.com>,
	Alexander Dahl <post@lespocky.de>
Cc: brgl@kernel.org, linux-gpio@vger.kernel.org,
	Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Subject: [PATCH 2/2] tools: reuse libgpiotools
Date: Wed, 13 May 2026 13:47:13 +0200	[thread overview]
Message-ID: <20260513-tools-common-shared-lib-v1-2-58ac28a9f1d5@oss.qualcomm.com> (raw)
In-Reply-To: <20260513-tools-common-shared-lib-v1-0-58ac28a9f1d5@oss.qualcomm.com>

Reuse as much of the functionality provided by the new libgpiotools
shared library in tools-common while retaining the functions used to
validate command-line arguments, print help text or bail-out on errors.
We keep the existing interfaces to gpio-tools and use them to wrap the
API exposed by libgpiotools as we want to keep bailing out on errors
without requiring tools to do a lot of repeated error checking.

Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
---
 tools/meson.build    |   8 +-
 tools/tools-common.c | 316 ++++++---------------------------------------------
 tools/tools-common.h |  63 +---------
 3 files changed, 47 insertions(+), 340 deletions(-)

diff --git a/tools/meson.build b/tools/meson.build
index d755167cfbd7c2a7400d28cf5e5d5f9eece699d7..5ecf7dc5d221d52243478f9a126e6512d2408981 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -21,9 +21,15 @@ pkgconfig.generate(libgpiotools_lib,
   version: meson.project_version(),
 )
 
+libgpiotools_dep = declare_dependency(
+  link_with: libgpiotools_lib,
+  include_directories: include_directories('.'),
+)
+
 tools_common_lib = static_library('tools-common',
   sources: ['tools-common.c'],
   include_directories: libgpiod_inc,
+  dependencies: [libgpiotools_dep],
   pic: true,
 )
 
@@ -33,7 +39,7 @@ tools_common_dep = declare_dependency(
 )
 
 tools_c_args = []
-tools_deps = [libgpiod_dep, tools_common_dep]
+tools_deps = [libgpiod_dep, libgpiotools_dep, tools_common_dep]
 
 if opt_gpioset_interactive.allowed() and libedit_dep.found()
   tools_c_args += ['-DGPIOSET_INTERACTIVE']
diff --git a/tools/tools-common.c b/tools/tools-common.c
index 5aa51197c521a373b421054459c8ef38f3a35a1e..56ed90f639790ec54a3d6e9eb6ad594104474d7e 100644
--- a/tools/tools-common.c
+++ b/tools/tools-common.c
@@ -4,8 +4,6 @@
 
 /* Common code for GPIO tools. */
 
-#include <ctype.h>
-#include <dirent.h>
 #include <errno.h>
 #include <gpiod.h>
 #include <inttypes.h>
@@ -14,7 +12,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sys/stat.h>
 #include <time.h>
 
 #include "tools-common.h"
@@ -431,154 +428,39 @@ void print_line_vals(struct line_resolver *resolver, bool is_unquoted,
 	printf("\n");
 }
 
-static int chip_dir_filter(const struct dirent *entry)
-{
-	struct stat sb;
-	int ret = 0;
-	char *path;
-
-	if (asprintf(&path, "/dev/%s", entry->d_name) < 0)
-		return 0;
-
-	if ((lstat(path, &sb) == 0) && (!S_ISLNK(sb.st_mode)) &&
-	    gpiod_is_gpiochip_device(path))
-		ret = 1;
-
-	free(path);
-
-	return ret;
-}
-
-static bool isuint(const char *str)
-{
-	for (; *str && isdigit(*str); str++)
-		;
-
-	return *str == '\0';
-}
-
 bool chip_path_lookup(const char *id, char **path_ptr)
 {
 	char *path;
 
-	if (isuint(id)) {
-		/* by number */
-		if (asprintf(&path, "/dev/gpiochip%s", id) < 0)
-			return false;
-	} else if (strchr(id, '/')) {
-		/* by path */
-		if (asprintf(&path, "%s", id) < 0)
-			return false;
-	} else {
-		/* by device name */
-		if (asprintf(&path, "/dev/%s", id) < 0)
-			return false;
-	}
-
-	if (!gpiod_is_gpiochip_device(path)) {
-		free(path);
-		return false;
-	}
-
-	*path_ptr = path;
+	path = gpiotools_chip_path_lookup(id);
+	if (path)
+		*path_ptr = path;
 
-	return true;
+	return !!path;
 }
 
 int chip_paths(const char *id, char ***paths_ptr)
 {
-	char **paths;
-	char *path;
+	int ret;
 
-	if (id == NULL)
-		return all_chip_paths(paths_ptr);
-
-	if (!chip_path_lookup(id, &path))
-		return 0;
-
-	paths = malloc(sizeof(*paths));
-	if (paths == NULL)
+	ret = gpiotools_chip_paths(id, paths_ptr);
+	if (ret < 0)
 		die_oom();
 
-	paths[0] = path;
-	*paths_ptr = paths;
-
-	return 1;
+	return ret;
 }
 
 int all_chip_paths(char ***paths_ptr)
 {
-	int i, j, num_chips, ret = 0;
-	struct dirent **entries;
-	char **paths;
+	int ret;
 
-	num_chips = scandir("/dev/", &entries, chip_dir_filter, versionsort);
-	if (num_chips < 0)
+	ret = gpiotools_all_chip_paths(paths_ptr);
+	if (ret < 0)
 		die_perror("unable to scan /dev");
 
-	paths = calloc(num_chips, sizeof(*paths));
-	if (paths == NULL)
-		die_oom();
-
-	for (i = 0; i < num_chips; i++) {
-		if (asprintf(&paths[i], "/dev/%s", entries[i]->d_name) < 0) {
-			for (j = 0; j < i; j++)
-				free(paths[j]);
-
-			free(paths);
-			return 0;
-		}
-	}
-
-	*paths_ptr = paths;
-	ret = num_chips;
-
-	for (i = 0; i < num_chips; i++)
-		free(entries[i]);
-
-	free(entries);
 	return ret;
 }
 
-static bool resolve_line(struct line_resolver *resolver,
-			 struct gpiod_line_info *info, int chip_num)
-{
-	struct resolved_line *line;
-	bool resolved = false;
-	unsigned int offset;
-	const char *name;
-	int i;
-
-	offset = gpiod_line_info_get_offset(info);
-	for (i = 0; i < resolver->num_lines; i++) {
-		line = &resolver->lines[i];
-		/* already resolved by offset? */
-		if (line->resolved && (line->offset == offset) &&
-		    (line->chip_num == chip_num)) {
-			line->info = info;
-			resolver->num_found++;
-			resolved = true;
-		}
-		if (line->resolved && !resolver->strict)
-			continue;
-
-		/* else resolve by name */
-		name = gpiod_line_info_get_name(info);
-		if (name && (strcmp(line->id, name) == 0)) {
-			if (resolver->strict && line->resolved)
-				die("line '%s' is not unique", line->id);
-			line->offset = offset;
-			line->info = info;
-			line->chip_num = resolver->num_chips;
-			line->resolved = true;
-			resolver->num_found++;
-			resolved = true;
-		}
-	}
-
-	return resolved;
-}
-
 /*
  * check for lines that can be identified by offset
  *
@@ -588,57 +470,23 @@ static bool resolve_line(struct line_resolver *resolver,
 bool resolve_lines_by_offset(struct line_resolver *resolver,
 			     unsigned int num_lines)
 {
-	struct resolved_line *line;
-	bool used = false;
-	int i;
-
-	for (i = 0; i < resolver->num_lines; i++) {
-		line = &resolver->lines[i];
-		if ((line->id_as_offset != -1) &&
-		    (line->id_as_offset < (int)num_lines)) {
-			line->chip_num = 0;
-			line->offset = line->id_as_offset;
-			line->resolved = true;
-			used = true;
-		}
-	}
-	return used;
+	return gpiotools_resolve_lines_by_offset(resolver, num_lines);
 }
 
 bool resolve_done(struct line_resolver *resolver)
 {
-	return (!resolver->strict &&
-		resolver->num_found >= resolver->num_lines);
+	return gpiotools_resolve_done(resolver);
 }
 
 struct line_resolver *resolver_init(int num_lines, char **lines, int num_chips,
 				    bool strict, bool by_name)
 {
 	struct line_resolver *resolver;
-	struct resolved_line *line;
-	size_t resolver_size;
-	int i;
-
-	resolver_size = sizeof(*resolver) + num_lines * sizeof(*line);
-	resolver = malloc(resolver_size);
-	if (resolver == NULL)
-		die_oom();
 
-	memset(resolver, 0, resolver_size);
-
-	resolver->chips = calloc(num_chips, sizeof(struct resolved_chip));
-	if (resolver->chips == NULL)
+	resolver = gpiotools_resolver_init(num_lines, lines, num_chips,
+					   strict, by_name);
+	if (!resolver)
 		die_oom();
-	memset(resolver->chips, 0, num_chips * sizeof(struct resolved_chip));
-
-	resolver->num_lines = num_lines;
-	resolver->strict = strict;
-	for (i = 0; i < num_lines; i++) {
-		line = &resolver->lines[i];
-		line->id = lines[i];
-		line->id_as_offset = by_name ? -1 : parse_uint(lines[i]);
-		line->chip_num = -1;
-	}
 
 	return resolver;
 }
@@ -647,72 +495,23 @@ struct line_resolver *resolve_lines(int num_lines, char **lines,
 				    const char *chip_id, bool strict,
 				    bool by_name)
 {
-	struct gpiod_chip_info *chip_info;
-	struct gpiod_line_info *line_info;
 	struct line_resolver *resolver;
-	int num_chips, i, offset;
-	struct gpiod_chip *chip;
-	bool chip_used;
-	char **paths;
-
-	if (chip_id == NULL)
-		by_name = true;
-
-	num_chips = chip_paths(chip_id, &paths);
-	if (chip_id && (num_chips == 0))
-		die("cannot find GPIO chip character device '%s'", chip_id);
-
-	resolver = resolver_init(num_lines, lines, num_chips, strict, by_name);
-
-	for (i = 0; (i < num_chips) && !resolve_done(resolver); i++) {
-		chip_used = false;
-		chip = gpiod_chip_open(paths[i]);
-		if (!chip) {
-			if ((errno == EACCES) && (chip_id == NULL)) {
-				free(paths[i]);
-				continue;
-			}
-
-			die_perror("unable to open chip '%s'", paths[i]);
-		}
-
-		chip_info = gpiod_chip_get_info(chip);
-		if (!chip_info)
-			die_perror("unable to get info for '%s'", paths[i]);
-
-		num_lines = gpiod_chip_info_get_num_lines(chip_info);
-
-		if (i == 0 && chip_id && !by_name)
-			chip_used = resolve_lines_by_offset(resolver, num_lines);
-
-		for (offset = 0;
-		     (offset < num_lines) && !resolve_done(resolver);
-		     offset++) {
-			line_info = gpiod_chip_get_line_info(chip, offset);
-			if (!line_info)
-				die_perror("unable to read the info for line %d from %s",
-					   offset,
-					   gpiod_chip_info_get_name(chip_info));
-
-			if (resolve_line(resolver, line_info, i))
-				chip_used = true;
-			else
-				gpiod_line_info_free(line_info);
-
-		}
+	int i;
 
-		gpiod_chip_close(chip);
+	resolver = gpiotools_resolve_lines(num_lines, lines, chip_id,
+					   strict, by_name);
+	if (!resolver) {
+		if (errno == ENODEV)
+			die("cannot find GPIO chip character device '%s'",
+			    chip_id);
+		else
+			die_perror("error resolving lines");
+	}
 
-		if (chip_used) {
-			resolver->chips[resolver->num_chips].info = chip_info;
-			resolver->chips[resolver->num_chips].path = paths[i];
-			resolver->num_chips++;
-		} else {
-			gpiod_chip_info_free(chip_info);
-			free(paths[i]);
-		}
+	for (i = 0; i < resolver->num_lines; i++) {
+		if (resolver->lines[i].not_unique)
+			die("line '%s' is not unique", resolver->lines[i].id);
 	}
-	free(paths);
 
 	return resolver;
 }
@@ -752,75 +551,30 @@ void validate_resolution(struct line_resolver *resolver, const char *chip_id)
 
 void free_line_resolver(struct line_resolver *resolver)
 {
-	int i;
-
-	if (!resolver)
-		return;
-
-	for (i = 0; i < resolver->num_lines; i++)
-		gpiod_line_info_free(resolver->lines[i].info);
-
-	for (i = 0; i < resolver->num_chips; i++) {
-		gpiod_chip_info_free(resolver->chips[i].info);
-		free(resolver->chips[i].path);
-	}
-
-	free(resolver->chips);
-	free(resolver);
+	gpiotools_free_line_resolver(resolver);
 }
 
 int get_line_offsets_and_values(struct line_resolver *resolver, int chip_num,
 				unsigned int *offsets,
 				enum gpiod_line_value *values)
 {
-	struct resolved_line *line;
-	int i, num_lines = 0;
-
-	for (i = 0; i < resolver->num_lines; i++) {
-		line = &resolver->lines[i];
-		if (line->chip_num == chip_num) {
-			offsets[num_lines] = line->offset;
-			if (values)
-				values[num_lines] = line->value;
-
-			num_lines++;
-		}
-	}
-
-	return num_lines;
+	return gpiotools_get_line_offsets_and_values(resolver, chip_num,
+						     offsets, values);
 }
 
 const char *get_chip_name(struct line_resolver *resolver, int chip_num)
 {
-	return gpiod_chip_info_get_name(resolver->chips[chip_num].info);
+	return gpiotools_get_chip_name(resolver, chip_num);
 }
 
 const char *get_line_name(struct line_resolver *resolver, int chip_num,
 			  unsigned int offset)
 {
-	struct resolved_line *line;
-	int i;
-
-	for (i = 0; i < resolver->num_lines; i++) {
-		line = &resolver->lines[i];
-		if (line->info && (line->offset == offset) &&
-		    (line->chip_num == chip_num))
-			return gpiod_line_info_get_name(
-				resolver->lines[i].info);
-	}
-
-	return 0;
+	return gpiotools_get_line_name(resolver, chip_num, offset);
 }
 
 void set_line_values(struct line_resolver *resolver, int chip_num,
 		     enum gpiod_line_value *values)
 {
-	int i, j;
-
-	for (i = 0, j = 0; i < resolver->num_lines; i++) {
-		if (resolver->lines[i].chip_num == chip_num) {
-			resolver->lines[i].value = values[j];
-			j++;
-		}
-	}
+	gpiotools_set_line_values(resolver, chip_num, values);
 }
diff --git a/tools/tools-common.h b/tools/tools-common.h
index 165c250f8d664687d06232426941020e0c8a4ae7..85ee765255bbba991cd2e1fbe6b727a9e998d47e 100644
--- a/tools/tools-common.h
+++ b/tools/tools-common.h
@@ -7,6 +7,8 @@
 
 #include <gpiod.h>
 
+#include "gpiotools.h"
+
 /*
  * Various helpers for the GPIO tools.
  *
@@ -19,64 +21,9 @@
 
 #define GETOPT_NULL_LONGOPT	NULL, 0, NULL, 0
 
-struct resolved_line {
-	/* from the command line */
-	const char *id;
-
-	/*
-	 * id parsed as int, if that is an option, or -1 if line must be
-	 * resolved by name
-	 */
-	int id_as_offset;
-
-	/* line has been located on a chip */
-	bool resolved;
-
-	/* remaining fields only valid once resolved... */
-
-	/* info for the line */
-	struct gpiod_line_info *info;
-
-	/* num of relevant chip in line_resolver */
-	int chip_num;
-
-	/* offset of line on chip */
-	unsigned int offset;
-
-	/* line value for gpioget/set */
-	int value;
-};
-
-struct resolved_chip {
-	/* info of the relevant chips */
-	struct gpiod_chip_info *info;
-
-	/* path to the chip */
-	char *path;
-};
-
-/* a resolver from requested line names/offsets to lines on the system */
-struct line_resolver {
-	/*
-	 * number of chips the lines span, and number of entries in chips
-	 */
-	int num_chips;
-
-	/* number of lines in lines */
-	int num_lines;
-
-	/* number of lines found */
-	int num_found;
-
-	/* perform exhaustive search to check line names are unique */
-	bool strict;
-
-	/* details of the relevant chips */
-	struct resolved_chip *chips;
-
-	/* descriptors for the requested lines */
-	struct resolved_line lines[];
-};
+#define resolved_line		gpiotools_resolved_line
+#define resolved_chip		gpiotools_resolved_chip
+#define line_resolver		gpiotools_line_resolver
 
 void set_prog_name(const char *name);
 const char *get_prog_name(void);

-- 
2.47.3


  parent reply	other threads:[~2026-05-13 11:47 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-13 11:47 [PATCH 0/2] tools: provide a shared library with high-level functions used by gpio-tools Bartosz Golaszewski
2026-05-13 11:47 ` [PATCH 1/2] tools: provide the libgpiotools shared library Bartosz Golaszewski
2026-05-13 11:47 ` Bartosz Golaszewski [this message]
2026-05-13 15:18 ` [PATCH 0/2] tools: provide a shared library with high-level functions used by gpio-tools Kent Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260513-tools-common-shared-lib-v1-2-58ac28a9f1d5@oss.qualcomm.com \
    --to=bartosz.golaszewski@oss.qualcomm.com \
    --cc=brgl@kernel.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=post@lespocky.de \
    --cc=vfazio@xes-inc.com \
    --cc=warthog618@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox